我正在尝试使用依赖项解析器创建简单的C ++增量构建工具。 我对cpp构建过程的一个问题感到困惑。 想象一下,我们有一个库包含几个文件:
// h1.h
void H1();
// s1.cpp
#include "h1.h"
#include "h2.h"
void H1(){ H2(); }
// h2.h
void H2();
// s2.cpp
#include "h2.h"
#include "h3.h"
void H2(){ /*some implementation*/ }
void H3(){ /*some implementation*/ }
// h3.h
void H3();
在客户端代码中包含h1.h
// app1.cpp
#include "h1.h"
int main()
{
H1();
return 0;
}
有s2.cpp实现的隐式依赖: our_src - > h3 - > s1 - > h2 - > S2。所以我们需要链接两个obj文件:
g++ -o app1 app1.o s1.o s2.o
相比之下,包括h3.h
// app2.cpp
#include "h3.h"
int main()
{
H3();
return 0;
}
只有一个源依赖: our_src - > h3 - > S2
所以当我们包含h3.h时,我们只需要编译s2.cpp(尽管s1.cpp - > h2.h包含):
g++ -o app2 app2.o s2.o
这是一个非常简单的问题示例,在实际项目中,我们肯定会有几百个文件,而低效的包含链可能包含更多文件。
所以我的问题是:当我们检查依赖关系时(没有CPP解析),是否有一种方法或工具可以找出哪些包含内容可以省略?
我很感激任何回应。
答案 0 :(得分:2)
如果您声明看到对s2.cpp的隐式依赖,则需要解析实现模块s1.cpp,因为只有在那里您才会发现s1模块正在使用s2。所以对于“如果不解析.cpp文件我能解决这个问题”的问题,答案显然是否定的。
就语言而言,在头文件或实现文件中可以放置的内容之间没有区别。 #include
指令在C ++级别不起作用,它只是一个文本宏函数,不需要理解语言。
而且即使解析“只是”C ++声明也是一个真正的噩梦(C ++语法的难点部分是声明,而不是语句/表达式)。
您可以使用解析C ++文件的gccxml结果并返回可以检查的XML数据结构。
答案 1 :(得分:0)
这不是一个容易的问题。只有很多事情让这很困难:
class Foo
中定义了foo.h
,但在foo_cotr_dotr.cpp
,foo_this_function.cpp
和foo_that_function.cpp
中实施了Foo::bar()
。foo_bar_linux.cpp
在foo_bar_osx.cpp
,foo_bar_sunos.cpp
,{{1}}中有实现。要使用的实现取决于目标平台。一个简单的解决方案是构建共享或动态库并链接到该库。让工具链解决这些依赖关系。问题#1完全消失,如果你有足够聪明的makefile,问题#2也会消失。
如果你坚持反对这个简单的解决方案,你将需要做一些事情来自己解决这些依赖关系。您可以通过项目规则一个头文件==一个源文件消除上述问题(不是详尽的列表)。我已经看过这样一条规则,但并不像我看到的一个项目规则那样频繁地说一个函数==一个源文件。
答案 2 :(得分:0)
您可以查看我如何实施Wand。它使用指令为各个源文件添加依赖项。文档尚未完全完成,但Gabi的源代码中有Wand指令的例子。
Thread.h在链接时需要thread.o
#ifdef __WAND__
dependency[thread.o]
target[name[thread.h] type[include]]
#endif
只有在Windows是目标平台时才能编译此文件
#ifdef __WAND__
target[name[thread.o] type[object] platform[;Windows]]
#endif
只有在GNU / Linux是目标平台时才能编译此文件。在GNU / Linux上,链接时需要外部库pthread。
#ifdef __WAND__
target
[
name[thread.o] type[object] platform[;GNU/Linux]
dependency[pthread;external]
]
#endif