可以使用哪些技术来加快c++编译时间?
这个问题出现在一些关于Stack Overflow问题c++编程风格的评论中,我很有兴趣听听有什么想法。
我看到过一个相关的问题,为什么c++编译要花这么长时间?,但这并没有提供很多解决方案。
可以使用哪些技术来加快c++编译时间?
这个问题出现在一些关于Stack Overflow问题c++编程风格的评论中,我很有兴趣听听有什么想法。
我看到过一个相关的问题,为什么c++编译要花这么长时间?,但这并没有提供很多解决方案。
当前回答
语言技巧
痘痘成语
看看这里和这里的impl习惯用法,也称为不透明指针或句柄类。它不仅加快了编译速度,还在与非抛出交换函数结合使用时提高了异常安全性。impl习惯用法让您减少了头文件之间的依赖关系,并减少了需要重新编译的数量。
提出声明
尽可能使用前向声明。如果编译器只需要知道SomeIdentifier是一个结构体或指针或其他什么,就不要包含整个定义,这会迫使编译器做更多的工作。这可能会产生级联效应,使这种方式比他们需要的更慢。
I/O流以降低构建速度而闻名。如果你需要它们在头文件中,尝试#包含<iosfwd>而不是<iostream>和#只在实现文件中包含<iostream>头。<iosfwd>报头只保存前向声明。不幸的是,其他标准标头没有各自的声明标头。
在函数签名中首选引用传递而不是值传递。这将消除在头文件中#include各自的类型定义的需要,您只需要向前声明类型。当然,更喜欢const引用而不是非const引用,以避免模糊的错误,但这是另一个问题。
守卫条件
使用保护条件可以防止头文件在一个翻译单元中被多次包含。
#pragma once
#ifndef filename_h
#define filename_h
// Header declarations / definitions
#endif
通过同时使用pragma和ifndef,你可以获得普通宏解决方案的可移植性,以及一些编译器在使用pragma once指令时可以实现的编译速度优化。
减少相互依存
一般来说,你的代码设计越模块化,依赖性越小,你需要重新编译的次数就越少。您还可以减少编译器同时在任何单个块上所做的工作量,因为它需要跟踪的工作量更少了。
编译器选项
预编译头文件
它们用于为多个翻译单元编译包含标题的公共部分。编译器编译它一次,并保存它的内部状态。然后可以快速加载该状态,以便在编译具有相同头集的另一个文件时抢占先机。
注意,在预编译的头文件中只包含很少更改的内容,否则您可能会更频繁地进行完全重建。这是一个存放STL头文件和其他库包含文件的好地方。
Ccache是另一个利用缓存技术来加快速度的实用程序。
使用并行性
许多编译器/ ide支持使用多个内核/ cpu同时进行编译。在GNU Make(通常与GCC一起使用)中,使用-j [N]选项。在Visual Studio中,在首选项下有一个选项,允许它并行构建多个项目。您还可以使用/MP选项进行文件级并行,而不仅仅是项目级并行。
其他并行工具:
Incredibuild 建立统一 distcc
使用较低的优化级别
编译器尝试优化的次数越多,它的工作就越困难。
共享库
将修改频率较低的代码移到库中可以减少编译时间。通过使用共享库(。或者。dll),你也可以减少链接时间。
换一台更快的电脑
更多的RAM,更快的硬盘驱动器(包括ssd),更多的cpu /内核都会使编译速度有所不同。
其他回答
升级你的电脑 获得一个四芯(或双四芯系统) 获得大量的内存。 使用RAM驱动器可以大大减少文件I/O延迟。(有些公司生产的IDE和SATA RAM驱动器就像硬盘驱动器一样)。 然后你有了所有其他典型的建议 如果可用,使用预编译头文件。 减少项目各部分之间的耦合。更改一个头文件通常不需要重新编译整个项目。
首先,我们必须了解c++与其他语言的不同之处。
有人说c++有太多的特性。但是,有些语言有更多的特性,它们远没有那么慢。
有人说文件的大小很重要。不,源代码行与编译时间无关。
等等,这怎么可能呢?代码行数越多,编译时间就越长,这是怎么回事?
诀窍在于很多代码行隐藏在预处理器指令中。是的。仅仅一个#include就会破坏模块的编译性能。
你看,c++没有模块系统。所有*.cpp文件都是从头编译的。因此,拥有1000 *.cpp文件意味着编译项目1000次。你还有更多?太糟糕了。
这就是为什么c++开发人员不愿意将类拆分为多个文件的原因。所有这些头文件的维护都很乏味。
那么,除了使用预编译的头文件、将所有cpp文件合并为一个文件并保持头文件的数量最小化之外,我们还能做什么呢?
c++ 20给我们带来了模块的初步支持!最终,您将能够忘记#include以及头文件带来的糟糕编译性能。碰过一个文件?只重新编译该文件!需要编译一个新的签出?以秒为单位编译,而不是以分钟和小时为单位。
c++社区应该尽快迁移到c++ 20。c++编译器开发人员应该更加关注这一点,c++开发人员应该开始测试各种编译器的初步支持,并使用那些支持模块的编译器。这是c++历史上最重要的时刻!
来自微软:https://devblogs.microsoft.com/cppblog/recommendations-to-speed-c-builds-in-visual-studio/
具体建议包括:
项目使用PCH吗 是否包含常用的系统、运行时和第三方头文件 PCH 在PCH中包含很少改变项目特定的头 不包括经常变化的头 是否定期审核PCH以保持产品流失的最新情况 使用/ mp 是否移除/Gm以支持/MP 是否解决与#import和use /MP的冲突 是否使用连接器开关/增量 使用链接器开关/调试:fastlink 是否考虑使用第三方构建加速器
网络共享将大大降低您的构建速度,因为查找延迟很高。对于像Boost这样的东西,它给我带来了巨大的不同,尽管我们的网络共享驱动器非常快。当我从网络共享切换到本地SSD时,编译一个玩具Boost程序的时间从大约1分钟缩短到1秒。
我将链接到我的另一个答案:如何减少Visual c++项目(原生c++)的编译时间和链接时间?我想补充的另一点是使用预编译的头文件,这经常会导致问题。但是,请只将它们用于几乎不会改变的部分(如GUI工具箱头)。否则,他们会花费你更多的时间,而不是他们最终节省你的时间。
另一个选项是,当你使用GNU make时,打开-j<N>选项:
-j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg.
我通常把它设置为3,因为我这里有一个双核。然后,它将为不同的翻译单元并行运行编译器,前提是它们之间没有依赖关系。链接不能并行完成,因为只有一个链接器进程将所有目标文件链接在一起。
但是链接器本身可以被线程化,这就是GNU gold ELF链接器所做的。它是优化的多线程c++代码,据说它链接ELF对象文件的速度比旧的ld快很多(实际上包含在binutils中)。