13

我发现如果有很多类,当我为每个类使用一个 *.h 和一个 *.cpp 文件时,编译时间会大大增加。我已经使用了预编译的头文件和增量链接,但是编译时间仍然很长(是的,我使用了 boost ;)

所以我想出了以下技巧:

  • 将 *.cpp 文件定义为不可编译
  • 将 *.cxx 文件定义为可编译
  • 每个应用程序模块添加一个*.cxx 文件,并#included 该模块的所有*.cpp 文件。

因此,我最终只得到了 8 个翻译单元,而不是 100 多个翻译单元。编译时间缩短了 4-5 倍。

缺点是您必须手动包含所有 *.cpp 文件(但这并不是真正的维护噩梦,因为如果您忘记包含链接器会提醒您的内容),并且某些 VS IDE 便利性不适用于此方案,例如转到/移至实施等。

所以问题是,拥有大量 cpp 翻译单元真的是唯一正确的方法吗?我的把戏是已知的模式,还是我遗漏了什么?谢谢!

4

8 回答 8

5

这种方法的一个重要缺点是每个翻译单元都有一个 .obj 文件。

如果您创建一个静态库以在其他项目中重用,如果您有几个巨大的翻译单元而不是许多小的翻译单元,那么您通常会在这些项目中面临更大的二进制文件,因为链接器只会包含包含真正引用的函数/变量的 .obj 文件在使用该库的项目中。

如果翻译单元较大,则更有可能引用每个单元并包含相应的 .obj 文件。在某些情况下,更大的二进制文件可能会成为问题。也有可能一些链接器足够聪明,只包含必要的函数/变量,而不是整个 .obj 文件。

此外,如果包含 .obj 文件并且也包含所有全局变量,那么它们的构造函数/析构函数将在程序启动/停止时被调用,这肯定需要时间。

于 2009-05-14T05:53:30.937 回答
4

我已经看到您在视频游戏中所做的事情,因为它可以帮助编译器进行优化,否则它无法做到以及节省大量内存。我见过“超级构建”和“批量构建”指的是这个想法。如果它有助于加快您的构建,为什么不...

于 2009-05-14T05:44:30.693 回答
3

将大量 C++ 源代码文件捆绑到一个文件中是最近多次提到的一种方法,尤其是当人们构建大型系统并引入复杂的头文件时(那将是提升)。

正如您提到的 VS,我发现项目中包含文件的数量,尤其是包含路径的大小,似乎对 Visual C++ 的编译时间的影响远远超过对 g++ 的编译时间的影响。尤其是有大量嵌套包含的情况(同样,boost 会这样做),因为需要大量文件搜索才能找到源代码所需的所有包含文件。将代码组合到单个源文件中意味着编译器可以更智能地查找所述包含,而且显然可以找到更少的包含,因为您期望同一子项目中的文件可能包含非常相似的一组头文件。

C++ 开发的“大量编译单元​​”方法通常来自于解耦类和最小化类之间的依赖关系的愿望,因此编译器只需重建最小的文件集以防您进行任何更改。这通常是一种好方法,但在子项目中通常并不可行,因为其中的文件相互依赖,因此无论如何您最终都会进行相当大的重建。

于 2009-05-14T06:28:42.833 回答
3

我不认为减少编译单元的数量是一个好主意。您正在尝试解决编译时间较长的问题,这种方法似乎对此有所帮助,但是您还得到了什么:

  1. 在开发过程中增加了编译时间。通常开发人员一次修改几个文件,对于 3-4 个小文件的编译可能会比一个非常大的文件更快。
  2. 正如您所提到的,更难导航代码,恕我直言,这非常重要。
  3. 您可能会在包含在一个 .cxx 文件中的 .cpp 文件之间产生一些干扰:

    一种。通常的做法是在 cpp 文件(用于调试构建)中本地定义宏 new 以进行内存泄漏检查。不幸的是,在使用placement new 包含标头之前无法做到这一点(正如某些STL 和BOOST 标头所做的那样)

    湾。在 cpp 文件中添加 using 声明是常见的做法。使用您的方法,这可能会导致标题出现问题,稍后会包含

    C。名称冲突的可能性更大

恕我直言,加快编译时间的更简洁(但可能更昂贵的方法)是使用一些分布式构建系统。它们对于干净的构建特别有效。

于 2009-05-14T07:04:34.450 回答
2

我不确定这是否与您的情况相关,但也许您可以使用声明而不是定义来减少#include您必须做的数量。此外,也许您可​​以将 pimpl 成语用于相同目的。这有望减少每次需要重新编译的源文件的数量以及必须拉入的头文件的数量。

于 2009-05-14T06:55:54.407 回答
1

更大和更少的翻译单元不会利用并行编译。我不知道您正在使用什么编译器和什么平台,但是并行编译多个翻译单元可能会显着减少构建时间......

于 2009-05-14T06:27:10.920 回答
1

这个概念被称为统一构建

于 2009-05-14T07:11:44.277 回答
0

继尖牙帖子之后,我倾向于更详细地检查生成的可执行文件。如果它们不同,我倾向于将您的技术限制为调试构建,并使用原始项目配置来进行主发布构建。在检查可执行文件时,我还会在启动和运行时查看它的内存占用和资源使用情况。

于 2009-05-14T06:31:45.620 回答