将所有的.cpp文件包含到一个单独的编译单元中?

10 浏览
0 Comments

将所有的.cpp文件包含到一个单独的编译单元中?

最近我有机会使用一些带有常见的Debug和Release配置的Visual Studio C++项目,但还有“Release All”和“Debug All”这两个我从未见过的配置。

原来项目的作者有一个名为ALL.cpp的文件,其中包含了所有其他.cpp文件。*All配置只构建这一个ALL.cpp文件。当然,ALL.cpp在常规配置中被排除在外,常规配置不会构建ALL.cpp。

我只是想知道这是否是一种常见的做法?它带来了什么好处?(我的第一反应是感觉不对劲。)

使用这种做法可能会遇到哪些问题?我能想到的一个问题是,如果你的.cpp文件中有匿名命名空间,它们将不再“私有”,而是在其他.cpp文件中也可见了。

所有项目都构建DLL,所以在匿名命名空间中存储数据可能不是一个好主意,对吗?但是函数则没问题吧?

0
0 Comments

#include all .cpp files into a single compilation unit? 这个问题的出现的原因是为了提高编译器对程序大小的优化能力。通常,某些优化只在不同的编译单元中执行,例如删除重复代码和内联。然而,最近的编译器(如Microsoft的、Intel的,但我认为不包括GCC)可以在多个编译单元之间执行这种优化,所以我怀疑这种“技巧”是不必要的。不过,很好奇是否确实有任何差别。现在,Visual C++可以使用/LTCG开关(链接时代码生成)进行整个程序优化,GCC和clang也支持LTO(链接时优化)。所以这是不必要的。这样做会大大减少速度和硬盘驱动器磁头运动的次数!

0
0 Comments

#include all .cpp files into a single compilation unit? 这个问题的出现是因为在C++项目中,有很多头文件被大部分或全部的CPP文件包含,而冗余的解析这些头文件是编译的主要成本,特别是当项目有很多短的源文件时。预编译头文件可以帮助减少这个成本,但通常有很多没有被预编译的头文件。

而将所有的CPP文件包含在一个单一的编译单元中,可以提高构建速度的原因有三个主要的原因。

首先,所有共享的头文件只需要解析一次。这意味着减少了冗余的头文件解析,特别是当有很多短的源文件时,这是编译的主要成本。预编译头文件可以帮助减少这个成本,但通常有很多没有被预编译的头文件。

其次,unity builds提高了构建速度,是因为编译器的调用次数减少了。调用编译器会有一些启动成本。

最后,减少了冗余的头文件解析意味着减少了内联函数的冗余代码生成,因此目标文件的总大小更小,这使得链接更快。

Unity builds还可以产生更好的代码生成。

Unity builds之所以快,并不是因为减少了磁盘I/O。我用xperf对许多构建进行了分析,所以我知道我在说什么。如果内存足够,操作系统的磁盘缓存将避免冗余的I/O,后续对头文件的读取将来自操作系统的磁盘缓存。如果内存不足,则Unity builds甚至可能使构建时间变得更慢,因为编译器的内存占用超过了可用内存并被分页出去。

磁盘I/O是昂贵的,这就是为什么所有操作系统都会积极缓存数据以避免冗余磁盘I/O的原因。

对于大型项目来说,构建速度没有其他替代方案更好。顺便说一句,建议使用msbuild /LTCG可以将链接时间从4分钟提高到一整夜!(Clang的效果更好)。

需要注意的是,VS 2015修复了下面列出的错误,这使得LTCG链接运行速度显著提高 - 在一些最近的大规模测试中提高了三倍的速度。

正确的答案是,C++编译速度慢,因为每个编译单元必须单独编译。

0
0 Comments

问题:如何将所有的.cpp文件包含到一个单独的编译单元中(#include all .cpp files into a single compilation unit?)?

原因:使用“Unity Build”可以实现快速链接和相对较快的编译速度。对于不需要迭代的构建,比如从中央服务器发布的构建,它非常有用。然而,它在维护方面可能会有些麻烦。

解决方法:使用“Unity Build”可以提高编译速度,因为编译器只需要一次读取所有内容,然后进行编译和链接,而不是针对每个.cpp文件都进行这些操作。此外,使用“Unity Build”可以避免多次编译头文件中的代码。可以通过以下链接获取更多关于“Unity Build”的信息:[http://buffered.io/posts/the-magic-of-unity-builds/](http://buffered.io/posts/the-magic-of-unity-builds/)。

一些其他的注意事项和解决方案也被提到过。例如,使用CMake可以从目标的源文件列表中生成“Unity Build”的.cpp文件。另外,使用闪存驱动器而不是旋转驱动器可以提高原始I/O的速度,但多次编译仍然是主要问题。此外,可以使用工具如[cotire](https://github.com/sakra/cotire)和[ucm](https://github.com/onqtam/ucm)来更方便地使用“Unity Build”。

使用“Unity Build”可以提高编译速度和链接速度,避免多次编译头文件中的代码。然而,它在维护方面可能会有些麻烦。可以通过使用CMake和其他相关工具来更方便地实现“Unity Build”。

0