在编译过程中include的文件会被多次访问, 每一个编译单元(Translation Unit,指的是编译出一个object文件的过程)都会访问到。除非你用一个固态磁盘,不然一般的硬盘一定会拖慢编译过程。
在示例的项目中,有两个假的编译单元,t1.cpp和t2.cpp,都包含相同的头文件ub/b.h, 而它自己又引用了ub/a.h。为了方便验证,在MSVC中打开showIncludes (译注:在项目属性里C/C++->Advanced->Show Includes), 你将看到一个类似这样的输出(*译注,如果没有看到,试试清一下工程再编译。):
Compiling...
t2.cpp
Note: including file: b.h
Note: including file: a.h
t1.cpp
Note: including file: b.h
Note: including file: a.h
可以看到,每个编译单元都打开了相同的头文件。UB的目的就是减少这些费时费力的事(比如. 引用的文件), 具体的做法就是将多个translation unit由一个单一的translation unit来代替。
新增一个文件ub.cpp, 内容如下:
#include <t1.cpp>
#include <t2.cpp>
Compiling...
ub.cpp
Note: including file: t1.cpp
Note: including file: b.h
Note: including file: a.h
Note: including file: t2.cpp
同样也是4个引用的文件。有没有性能提升呢? 结果是肯定的,第一次遇到b.h会同时引发对a.h的解析,可是第二次遇到b.h时就不需要再解析了。
对于一些有着很深的引用层次和大量编译单元的项目来说,Unity Builds的做法绝对会节省大量的编译时间。
/*译注,作者下面介绍了为CMake编写的自动脚本,此处略去。具体的应用还是要看各个编译器的做法。*/
性能提升
下面这个图显示出了Unity Builds对于编译时间的贡献。所用的项目都是由公司开发的一些库和单元测试项目。
实践要点
持续集成
相对于The Magic of Unity Builds中观点, 因为一点修改会导致整个unity unit的重新编译,所以最好不要用于平时的开发工作。倒是可以考虑在CI服务器上执行,这样可以节省大量的时间来跑自动化测试。
单元切分
在一个unity unit包含太多的文件,可能会引起内存不足的问题。即便你的内存够大,最好也不要都放在一起。
代码质量
引入Unity Builds会隐藏一些编码问题,比如重复的代码。因为是将一些translation unit放到一起,就很容易导致重复定义的问题。
原文地址: Reducing Compilation Time: Unity Builds
转载请注明出处: http://blog.csdn.net/horkychen
链接:
* Unity Builds CMake Demo Project
* The Evils of Unity Builds
* 浅谈怎样加快C++代码的编译速度