减少cpp翻译单元的数量是一个好主意吗?

时间:2009-05-14 05:35:38

标签: c++ performance build-process module header-files

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

所以我想出了以下技巧:

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

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

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

所以问题是,有很多cpp翻译单元真的是唯一真正的方法吗?我的伎俩是一种已知的模式,还是我错过了什么? 谢谢!

8 个答案:

答案 0 :(得分:5)

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

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

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

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

答案 1 :(得分:4)

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

答案 2 :(得分:3)

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

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

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

答案 3 :(得分:3)

我认为减少编译单元的数量并不是一个好主意。你正在尝试用大的编译时间解决问题,这种方法似乎对它有所帮助,但你得到的还有:

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

    一个。通常的做法是在cpp文件中本地定义(用于调试版本)宏新的内存泄漏检查。不幸的是,在使用placement new(包括某些STL和BOOST头)之前包含头文件之前无法做到这一点

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

    ℃。名称冲突更有可能

  4. 恕我直言,更加清洁(但可能更昂贵的方式)来加快编译时间是使用一些分布式构建系统。它们对于清洁构建尤其有效。

答案 4 :(得分:2)

我不确定这是否与您的情况相关,但也许您可以使用声明而不是定义来减少您必须执行的#include的数量。此外,也许你可以使用pimpl习语来达到同样的目的。这有望减少每次需要重新编译的源文件数量以及必须提取的标头数量。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

这个概念叫做unity build

答案 7 :(得分:0)

从sharptooths帖子开始,我倾向于详细检查生成的可执行文件。如果它们不同,我倾向于限制您的技术来调试构建并使用主要版本构建的原始项目配置。在检查可执行文件时,我还会查看启动时和运行时的内存占用和资源使用情况。