如何加快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 ++编译使用多核