如何加快g ++编译时间(使用大量模板时)
这个问题可能有点奇怪,但是我怎样才能加快编译时间? 我的C ++代码大量使用boost和模板。 我已经尽可能多地从头文件中移出并使用了-j选项,但编译(和链接)仍然需要相当长的一段时间。
有没有分析我的代码的工具,并指出了编译器的瓶颈? 或者可以以某种方式configuration运行在我的代码上的编译器? 这将是非常好的,因为有时我有印象,我花了太多的时间凝视编译器控制台日志…
什么对我最有用:
- build立在一个RAM文件系统上。 这在Linux上是微不足道的。 你可能想在RAM文件系统上保留一个常见的头文件(预编译的或者实际的.h文件)的副本。
- 预编译头文件 我有一个(主要)库(例如Boost,Qt,stdlib)。
- 在可能的情况下声明,而不是包含类。 这减less了依赖关系,从而减less了更改头文件时需要重新编译的文件的数量。
- 并行化 。 这通常有助于个案的基础上,但我有
-j3
全球作出。 确保你的依赖图在你的Makefile中是正确的,或者你可能有问题。 - 如果您不testing执行速度或代码大小,则使用
-O0
(而且您的计算机速度足够快,因为您不必太在意(可能很小)的性能问题)。 - 编译每次保存。 有些人不喜欢这样,但是它可以让你早日发现错误,并且可以在后台完成,减less了你完成写作并准备testing的时间。
下面是我已经做了什么来加速build立在一个非常相似的情况下,你描述(升压,模板,海合会)
- build立在本地磁盘上,而不是NFS等networking文件系统
- 升级到更新版本的gcc
- 调查distcc
- 更快的构build系统,特别是更多的RAM
我假设我们正在谈论几分钟来编译一个文件,即预编译头文件或本地磁盘问题不是问题。
编译时间长的模板代码(boost等)通常植根于gcc在模板实例化过程中不友好的渐近行为,特别是当模板默认参数模拟可变参数模板时。
下面是一个文档,其中将编译时间缩短为可变参数模板的动机:
cpptruths有一篇关于gcc-4.5如何更好的文章,以及它如何使用可变参数模板:
IIRC然后BOOST有办法限制伪variables的模板默认参数的生成,我认为'g ++ -DBOOST_MPL_LIMIT_LIST_SIZE = 10'应该工作(默认是20)
更新:也有一个很好的线程与一般的技术,以加快在SO编译这可能是有用的:
- 什么技术可以用来加快C ++编译时间?
更新:这是关于编译模板时的性能问题,接受的答案也build议使用gcc-4.5,也提到clang是一个正面的例子:
- 有优化的c + +编译器模板使用?
如果您正在进行大量的重新编译, ccache可能会有所帮助。 它实际上并没有加快编译速度,但是如果你由于某种原因碰巧做了无用的重新编译,它会给你一个caching的结果。 这可能给人一种解决错误问题的印象,但是有时候重build规则如此复杂,以至于在新的构build过程中,实际上最终会得到相同的编译步骤。
另外的想法:如果你的代码用clang编译,用它来代替。 它通常比gcc快。
除了其他人添加的内容以及您已经在做什么(并行编译,编译器选项等)之外,还可以考虑在实现类中隐藏模板,通过接口访问模板。 这意味着,而不是像以下类:
// ClsWithNoTemplates.h file, included everywhere class ClsWithTemplates { ComplicatedTemplate<abc> member; // ... public: void FunctionUsingYourMember(); };
你应该有:
// ClsWithNoTemplates.h file: class ClsWithTemplatesImplementation; // forward declaration // definition included in the ClsWithNoTemplates.cpp file // this class will have a ComplicatedTemplate<abc> member, but it is only // included in your ClsWithNoTemplates definition file (that is only included once) class ClsWithNoTemplates { ClsWithTemplatesImplementation * impl; // no templates mentioned anywhere here public: void FunctionUsingYourMember(); // call impl->FunctionUsingYourMember() internally };
这有点改变你的OOPdevise,但是它的好处是:包括'ClsWithNoTemplates'的定义现在是快速的 ,你只需要(预先)编译'ClsWithNoTemplates'的定义一次。
此外,如果更改实现代码,则包含ClsWithNoTemplates.h的任何代码都可能不需要重新定义。
这个改变会大大增加你的部分编译时间,而且在你的ClsWithNoTemplates是一个从库文件导出的公共接口的情况下也会有帮助:因为当你只改变实现时文件没有改变,根本不需要重新编译。
尝试PIMPL技术,这个问题: 什么技术可以用来加快C ++编译时间?
它会阻止编译器在每次需要执行某些操作时都跟随头文件链和实现。
如果有很多文件,只要有一个包含所有其他.cpp文件的.cpp文件就可以加快编译速度。 这当然要求你对macros更加小心,并且你已经定义了每个文件,因为它们现在对其他cpp文件是可见的。
如果有多个文件,这可以减less很多编译时间。
实例化较less的模板和内联函数。 尽可能多地进行预编译,只需将其链接起来,而不是从头开始编译所有内容。 确保你使用的是最新版本的GCC。
然而,C ++是一个非常复杂的语言,编译需要相当长的时间,这是一个简单的事实。
本文描述了一种非常类似于“传统”非模板对象文件的编译模板代码的方法。 保存编译和链接时间,每个模板实例只有一行代码开销。
通常,编译中最昂贵的部分是(a)读取源文件( 所有这些文件)和(b)将编译器加载到每个源文件的内存中。
如果你有52个源文件(.cc),其中每个文件包括47个#include(.h)文件,你将要加载52次编译器,而你将通过2496个文件进行压缩。 根据文件中的注释密度,你可能会花费大量的时间吃无用的字符。 (在我看到的一个组织中,头文件在66%到90%之间变化,只有10%-33%的文件是“有意义的”。为了提高这些文件的可读性,最好的做法是去掉每一个最后的评论,只留下代码。)
长时间看看你的程序是如何组织的。 看看你是否可以合并源文件,并简化#include文件的层次结构。
几十年前,像IBM这样的公司就理解了这一点,并且会编写他们的编译器,以便编译器能够交付一个文件列表来编译,而不仅仅是一个文件,编译器只会被加载一次。
用g ++编译使用多核
用g ++编译使用多核