C++;报头实现报头实现依赖链 我试图用依赖性分解器创建简单的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.hC++;报头实现报头实现依赖链 我试图用依赖性分解器创建简单的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();,c++,compiler-construction,build,incremental-build,C++,Compiler Construction,Build,Incremental Build,在客户端代码中时,包括h1.h // app1.cpp #include "h1.h" int main() { H1(); return 0; } s2.cpp实现存在隐式依赖关系: 我们的_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; } 只有一
// app1.cpp
#include "h1.h"
int main()
{
H1();
return 0;
}
s2.cpp实现存在隐式依赖关系:
我们的_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;
}
只有一个源依赖项:
我们的_src->h3->s2
因此,当我们包含h3.h时,只需要编译s2.cpp(尽管包含s1.cpp->h2.h):
这是一个非常简单的问题示例,在实际项目中,我们可能有数百个文件,而无效的包含链可能包含更多的文件
所以我的问题是:当我们检查依赖项时(没有CPP解析),有没有一种方法或工具可以找出哪些头包含可以省略
如果您能给我回复,我将不胜感激。这不是一个容易的问题。这其中有很多困难:
类Foo
在Foo.h
中定义,但在Foo\u cotr\u dotr.cpp
中实现,Foo\u this\u function.cpp
和Foo\u that\u function.cpp
Foo::bar()
在Foo\u bar\u linux.cpp
,Foo\u bar\u osx.cpp
,Foo\u bar\u sunos.cpp
中有实现。要使用的实现取决于目标平台如果你坚持反对这个简单的解决方案,你需要自己做些事情来解决这些依赖关系。您可以通过项目规则“一个头文件==一个源文件”来消除上述问题(不是详尽的列表)。我见过这样一个规则,但不像我见过的项目规则那样频繁,它说一个函数==一个源文件。在您声明要查看对s2.cpp的隐式依赖的情况下,您需要解析实现模块s1.cpp,因为只有在那里,您才会发现s1模块正在使用s2。因此,对于“我能在不解析.cpp文件的情况下解决这个问题”这个问题,答案显然是否定的 顺便说一句,就语言而言,在头文件或实现文件中可以放置的内容没有区别。<>代码>包含指令不在C++级别工作,它只是文本宏函数,不理解语言。 此外,即使解析“仅仅”C++声明也是一个真正的噩梦(C++语法的难点是声明,而不是语句/表达式)。
可以使用该解析C++文件的结果,并返回一个可以检查的XML数据结构。
< p>您可以查看我是如何实现的。它使用指令为单个源文件添加依赖项。文档尚未完全完成,但Gabi的源代码中有Wand指令的示例 例子 线程类包含文件 Thread.h在链接时需要Thread.o#ifdef __WAND__
dependency[thread.o]
target[name[thread.h] type[include]]
#endif
线程类在windows上的实现(Thread-win32.cpp)
仅当Windows是目标平台时才应编译此文件
#ifdef __WAND__
target[name[thread.o] type[object] platform[;Windows]]
#endif
GNU/Linux上的线程类实现(Thread Linux.cpp)
仅当GNU/Linux是目标平台时,才应编译此文件。在GNU/Linux上,链接时需要外部库pthread
#ifdef __WAND__
target
[
name[thread.o] type[object] platform[;GNU/Linux]
dependency[pthread;external]
]
#endif
利弊
赞成的意见
- Wand可以扩展到其他编程语言
- Wand只需发出Wand命令,即可保存成功链接新程序所需的所有必要数据
- 项目文件不需要提及任何依赖项,因为它们存储在源文件中
- Wand在每个源文件中都需要额外的指令
- 该工具尚未被图书馆作者广泛使用
#ifdef __WAND__
target
[
name[thread.o] type[object] platform[;GNU/Linux]
dependency[pthread;external]
]
#endif