3

我正在尝试使用依赖解析器创建简单的 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 解析)时,有没有办法或工具来找出可以省略哪些标头包含?

我会很感激任何回应。

4

3 回答 3

3

在您声明要查看对 s2.cpp 的隐式依赖的情况下,您需要解析实现模块 s1.cpp,因为只有在那里您才会发现 s1 模块正在使用 s2。所以对于“我可以在不解析 .cpp 文件的情况下解决这个问题吗”这个问题,答案显然是否定的。

顺便说一句,就语言而言,您可以放入头文件或实现文件中的内容没有区别。该#include指令在 C++ 级别不起作用,它只是一个文本宏函数,对语言没有任何理解。此外,即使解析“只是”C++ 声明也是一场真正的噩梦(C++ 语法的困难部分是声明,而不是语句/表达式)。

可能您可以使用解析 C++ 文件并返回可检查的 XML 数据结构的gccxml的结果。

于 2011-09-25T17:51:41.067 回答
0

这不是一个容易的问题。只有几件事使这变得困难:

  1. 如果在 N>1 个源文件中实现一个头文件怎么办?例如,假设在、和class Foo中定义foo.h但在 中实现。foo_cotr_dotr.cppfoo_this_function.cppfoo_that_function.cpp
  2. 如果在多个源文件中实现相同的功能怎么办?例如,假设在, ,Foo::bar()中有实现。要使用的实现取决于目标平台。foo_bar_linux.cppfoo_bar_osx.cppfoo_bar_sunos.cpp

一种简单的解决方案是构建一个共享或动态库并链接到该库。让工具链解决这些依赖关系。问题#1 完全消失了,如果你有一个足够聪明的makefile,问题#2 也会消失。

如果您坚持反对这个简单的解决方案,您将需要自己解决这些依赖关系。您可以通过项目规则一个头文件 == 一个源文件来消除上述问题(不是详尽的列表)。我见过这样的规则,但不像我见过的项目规则那样频繁,它说一个函数 == 一个源文件。

于 2011-09-25T17:47:57.797 回答
0

你可以看看我是如何实现Wand的。它使用指令为各个源文件添加依赖项。文档尚未完全完成,但在 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 在每个源文件中都需要额外的指令
  • 该工具尚未被图书馆作者广泛使用
于 2014-04-07T08:28:46.953 回答