C++ 减少cpp翻译单元的数量是一个好主意吗?
我发现,如果有很多类,当我为每个类使用一个*.h和一个*.cpp文件时,编译时间会显著增加。我已经使用了预编译头和增量链接,但编译时间仍然很长(是的,我使用boost;) 所以我想出了以下窍门:C++ 减少cpp翻译单元的数量是一个好主意吗?,c++,performance,build-process,module,header-files,C++,Performance,Build Process,Module,Header Files,我发现,如果有很多类,当我为每个类使用一个*.h和一个*.cpp文件时,编译时间会显著增加。我已经使用了预编译头和增量链接,但编译时间仍然很长(是的,我使用boost;) 所以我想出了以下窍门: 将*.cpp文件定义为不可编译 将*.cxx文件定义为可编译文件 为每个应用程序添加了一个*.cxx文件 模块,并且#包含此模块的所有*.cpp文件 因此,我最终只得到了8个翻译单元,而不是100多个翻译单元。编译时间缩短了4-5倍 缺点是,您必须手动包含所有*.cpp文件(但这并不是一个维护噩梦,
- 将*.cpp文件定义为不可编译
- 将*.cxx文件定义为可编译文件
- 为每个应用程序添加了一个*.cxx文件 模块,并且#包含此模块的所有*.cpp文件
谢谢 我见过你在视频游戏中所做的事情,因为它可以帮助编译器进行优化,否则它除了可以节省大量内存外,还无法进行优化。我见过“优步构建”和“批量构建”都是指这个想法。如果它有助于加快构建速度,为什么不..这种方法的一个显著缺点是每个翻译单元有一个.obj文件 如果您创建一个静态库以便在其他项目中重用,那么如果您有多个大型转换单元而不是许多小型转换单元,那么在这些项目中您通常会遇到更大的二进制文件,因为链接器将只包含.obj文件,其中包含使用库的项目中真正引用的函数/变量 对于大的翻译单元,更有可能引用每个单元并包含相应的.obj文件。在某些情况下,较大的二进制文件可能是一个问题。也可能有些链接器足够聪明,只包含必要的函数/变量,而不包含整个.obj文件
此外,如果包含.obj文件,并且也包含所有全局变量,那么当程序启动/停止时,将调用它们的构造函数/析构函数,这肯定需要时间。较大和较小的翻译单元不会利用并行编译。我不知道你在使用什么编译器和什么平台,但是编译多个翻译单元可能会大大缩短构建时间… 捆绑大量C++源代码文件到一个文件中是最近几次提到的一种方法。尤其是当人们在构建大型系统和引入复杂的头文件时(那将是boost) 正如您提到的VS一样,我发现项目中包含文件的数量,尤其是包含路径的大小,似乎对Visual C++的编译时间的影响远远大于对g++编译时间的影响。对于大量嵌套的include(boost也是这样做的),尤其如此,因为要查找源代码所需的所有include文件,需要进行大量的文件搜索。将代码合并到一个源文件中意味着编译器可以更智能地查找所述包含,而且可以找到的包含明显较少,因为您可以预期,同一子项目中的文件可能包含一组非常相似的头文件
C++开发中的“编译单元”通常来自于对类进行解耦并最小化类之间的依赖关系,因此编译器只需重建最小的文件集,以防发生任何更改。这通常是一种很好的方法,但通常在子项目中并不切实可行,因为其中的文件相互依赖,因此最终将进行相当大的重建。
继Sharptouths post之后,我倾向于详细检查生成的可执行文件。如果它们不同,我倾向于将您的技术限制在调试构建上,并求助于主发布构建的原始项目配置。在检查可执行文件时,我还会查看它在启动和运行时的内存占用和资源使用情况。我不确定这是否与您的情况相关,但也许您可以使用声明而不是定义来减少必须执行的#include
。此外,也许您可以出于同样的目的使用pimpl习语。这将有望减少每次需要重新编译的源文件的数量以及必须拉入的头文件的数量。我认为减少编译单元的数量不是一个好主意。您正试图用大量的编译时间来解决一个问题,这种方法似乎有助于解决这个问题,但您还得到了: