如何提高Visual C++编译时间?

50

我正在一个buildbot上编译两个C++项目,每次提交都要编译。这两个项目分别有约1000个文件,一个有100 kloc,另一个有170 kloc。从gcc(4.4)到Visual C++(2008),编译时间差异很大。

对于其中一个项目的Visual C++编译需要20分钟。由于一个项目依赖于另一个项目,因此无法利用多个核心。最终,在Debug和Release,32位和64位下,两个项目的全部8个版本都要花费超过2个半小时来完成编译。

而对于其中一个项目的gcc编译只需要4分钟。它可以在4个核心上并行处理,并且大约需要1分10秒的时间。四个版本(Debug/Release,32/64位)的两个项目的所有8个构建都可以在不到10分钟内编译完成。

Visual C++编译时间为什么会这么慢?它们的速度基本上是慢了5倍。

在编译C++ kloc时可以期望的平均时间是多少?我的vc++为7 s/kloc,而gcc为1.4 s/kloc。

在Visual C++上,有什么方法可以加快编译时间吗?


3
磁盘只有三分之一的容量被使用。我怀疑碎片和DLL副本能够将编译时间缩短5倍!也许只有10%左右,但不会更多。 - Didier Trosset
谢谢你的分数...但我只是好奇...是头文件中的实例化出了问题,还是我提到的其他事情之一? - user180326
有一个非常有帮助的方法是将所有临时、中间和pch文件移动到RAM磁盘上,但即使Windows机器有SSD,Linux机器有HD,速度仍然不如GCC快。我们在双路Xeon E5440上编译,我发现“make -j33”比人们推荐的“-j9”具有更好的编译时间(我运行了一个简单的脚本来测试从0到99的每个-j设置)。 - kfsone
12个回答

17

VC++编译器减速的一个原因是,如果您有一个头文件来初始化非平凡const值类型的具体实例。您可能会看到这种情况发生在std::string或GUID类型的常量中。它影响编译和链接时间。

对于单个dll,这导致了10倍的减速。如果将它们放在预编译头文件中,或者只在头文件中声明并在cpp文件中初始化,可以帮助解决问题。

确保检查病毒扫描程序,并尝试使用预编译头文件,否则您将无法看到VC++的最佳表现。

还要确保%TMP%文件夹与构建写入的分区相同,因为VC++会创建临时文件并稍后移动它们。


1
我对第一个问题很好奇;如果没有多个定义,你怎么能在头文件中定义变量呢?除非当然是因为它被define或未命名的命名空间更改了,但在这些情况下,我想这与在cpp文件中定义它们是相同的,不是吗? - ltjax
在我的情况下,它们被声明为const。我会进行编辑。我没有编写这段代码。我通过提前声明名称并在cpp文件中初始化来修复它们。 - user180326
在接受的答案中,删除静态关键字会导致编译时间巨大,这可能与避免编译器限制编译器堆栈溢出有关。 - paulm

10

互相依赖的项目并不意味着不能进行并行处理。构建系统足够智能,可以找出并避免关键依赖性,否则gcc就无法使用4个内核。

所以(除了其他措施之外),为什么不尝试在Visual Studio中启用多进程处理,使用/MP选项(请参见http://msdn.microsoft.com/en-us/library/bb385193.aspx)。


2
因为Visual Studio中的多进程无法按编译单元(.cpp文件)拆分工作,只能按项目进行! - Didier Trosset
2
奇怪的是,在我的机器上(并根据上面引用的文档),即使只构建一个项目,VS2008、VS2010 Beta2也会使用多个核心。 - jdisk
6
VS2008可以通过编译单元来实现拆分,这就是/MP标志的作用。在VS2005中,唯一可用的并行化形式是按项目划分。 - jalf
1
由于 /MP 与 /Gm(增量构建)不兼容,应该选择哪一个?要么在开发人员工作站上慢,要么在自动化构建上慢。 - Didier Trosset
5
为什么两者都必须使用完全相同的标志?让自动构建使用 /MP,如果/Gm在开发人员机器上更快,则应在那里使用。 - jalf

6
你是如何构建Visual Studio项目的?你只是使用项目和/build运行ide(devenv),还是有一个类似于你为gcc使用的makefile。我假设两个构建都使用类似的makefile,但我认为这值得检查。
你是否为任一编译器使用预编译头文件?如果你在VS中没有使用预编译头文件,那么你可能想要切换到使用它们。就个人而言,我建议使用#pragma hdrstop方法而不是一个单一的全包含头文件,但如果你目前没有使用预编译头文件并想尝试它,一个单一的全包含头文件可以快速测试,而不需要进行任何代码更改。
我在这里写了关于/FI和#pragma hdrstop的内容:http://www.lenholgate.com/blog/2004/07/fi-stlport-precompiled-headers-warning-level-4-and-pragma-hdrstop.html

我正在使用vcbuild.exe在命令行上编译Visual Studio项目。(MSBuild.exe或devenv.exe /build的持续时间相同) - Didier Trosset
对于 /FI 标志,我会给予加分。但我并不是 #pragma hdrstop 的忠实粉丝。 - Manuel
@Manuel,你为什么不喜欢#pragma hdrstop?它是一种非常方便的方式,可以允许干净的最小依赖构建,无需预编译,以及使用预编译头文件进行快速构建,这是我认为确保代码仅包含所需内容的绝佳方式,使其更易于重用... - Len Holgate
@Len - 也许我没有理解hdrstop的重点,但我认为我可以通过/FI实现相同的效果,而且不需要以任何方式修改我的源文件。 - Manuel
@Manuel,#pragma hdrstop 允许更精细地调整需要放入预编译头文件的内容和可以包含在C++文件中的内容,相较于使用 /FI 方法,它的使用方式略微更加明显。 - Len Holgate

6

2
Incredibuild可以利用多台计算机上的CPU核心,但当前项目设置未能充分利用本地计算机上的所有核心。也就是说,您首先需要解决并行化的这个层面。 - MSalters

3

约翰·拉科斯的《大规模C++软件设计》一书包含许多有关为大型项目构建代码和设计的技巧,其中包括许多加快编译速度的技巧。虽然与Visual C++没有直接关系,但无论如何阅读都是值得的。


2

我已经写了两篇有关减少编译时间技术的文章。其中一篇是关于预编译头文件,另一篇是关于统一构建,这些技术可以帮助您改善编译时间。它们附带了处理这些技术的CMake脚本,可以透明地处理。


1
首先,在大多数情况下,你可以并行构建同一项目的调试和发布配置。
其次,你所描述的情况听起来非常慢 - 看起来你没有在 VC++ 中使用预编译头文件或者使用方法不正确 - 它们被专门设计用来提高编译时间。

我完全没有使用预编译头文件。无论是在vc++还是g++中都没有使用。 - Didier Trosset

1

可能存在依赖检查问题,除非您强制进行完全重建。

您可以创建一些静态库。将很少更改的代码放入库中。

构建程序最慢的部分:

  1. 打开和关闭文件。
  2. 解析和翻译源文件。

通常情况下,链接和可执行文件创建阶段是最快的。

您确定了吗:

  1. 哪些阶段最慢?
  2. 哪些文件编译最慢?

请记住,在确定效率时,始终以某种方式进行分析。


0

你是在同一台机器上构建吗?你使用的是相同的操作系统吗?我曾经看到过在比较Cygwin中的GCC和运行在Windows主机内部的VirtualBox机器中的GCC时,速度差异在3-10倍左右。


它们不是同一台机器,但它们是等效的。Visual Studio运行在Windows XP 32位系统上。gcc运行在虚拟化的Debian Linux 32位系统上! - Didier Trosset
根据我的经验,这可能解释了整个时间差异。不确定该怎么办 - 或许在Debian环境中通过Wine运行MS编译器?您是否需要MS编译器,或者可以切换到Mingw?如果是这样,您可以从Debian设置进行交叉编译。 - e8johan

0

看起来非常奇怪,为什么会有这样的差异...但您也可以利用Visual上的多核心!

基本上,您有4种编译模式:(Debug / Release)x(32位/64位),每个模式都是完全独立的,您可以完美地并行运行这4个模式,充分利用可用的4个核。或者在Visual Studio上尝试MultiProcessor方法。

但这还不够。 150分钟对比10分钟是一个巨大的差距。从我的个人经验来看,在减少编译时间方面有两个主要因素:

  • 将所有使用的文件放在本地磁盘上(必要时使用来自远程磁盘的复制),并在本地创建所有文件(.o .so)
  • 利用您拥有的所有核心,如果可能,甚至使用多台机器(如distcc等)

也许我可以尝试一下,运行vcbuild.exe来同时构建相同项目但不同配置的版本。 - Didier Trosset
我无法在Visual上利用多核的原因是:Visual C++不支持同时编译同一项目中的多个文件。 - Didier Trosset
部分正确,因为 /MP 选项与我们所有 Debug 构建设置的 /Gm 选项(增量构建)不兼容。有趣的是,我们在开发人员工作站构建和自动化构建机构建中使用相同的项目。 - Didier Trosset

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接