VS 2008 C ++构建输出?

时间:2010-03-04 05:16:41

标签: c++ visual-studio compiler-construction msbuild visual-c++

为什么当我在VS中看VC ++项目的构建输出时,我看到了:

  

1>编译...
  1 GT; a.cpp
  1 GT; b.cpp
  1 GT; c.cpp
  1 GT; d.cpp
  1 GT; e.cpp
  [等等]
  1>生成代码...
  1 GT; x.cpp
  1 GT; y.cpp的
  [等等...]

在生成任何代码之前,输出看起来好像正在处理几个编译单元。这真的发生了吗?我正在尝试改善构建时间,并且通过使用预编译的头文件,我为每个“.cpp”文件获得了很大的加速,但是在“生成代码...”消息期间有一个相对较长的暂停。我没有启用“整个程序优化”或“链接时间代码生成”。如果是这样的话,为什么呢?为什么VC ++不单独编译每个“.cpp”(包括代码生成阶段)?如果这不只是输出的假象,那么交叉编译单元优化是否会在这里进行?似乎没有任何编译器选项来控制该行为(我知道WPO和LTCG,如上所述)。

修改
构建日志只显示输出目录中的“.obj”文件,每行一个。没有迹象表明“编译......”与“生成代码......”步骤。

修改
我已经确认此行为与工具中的“最大并行项目构建数”设置无关 - >选项 - >项目和解决方案 - >构建并运行。它也与 MSBuild项目构建输出详细程度设置无关。实际上,如果我在“生成代码...”步骤之前取消构建,则最新的“已编译”文件集中不会存在任何“.obj”文件。这意味着编译器真正在一起处理多个翻译单元。这是为什么?

5 个答案:

答案 0 :(得分:5)

编译器架构

编译器不直接从源代码生成代码,它首先将其编译为中间形式(请参阅compiler front-end),然后从中间形式生成代码,包括任何优化(请参阅compiler back-end )。

Visual Studio编译器进程生成

在Visual Studio构建中,执行编译器进程(cl.exe)以在一个命令中编译共享相同命令行选项的多个源文件。编译器首先按顺序对每个文件执行“编译”(这很可能是前端),但是一旦使用它们编译完成,所有文件的“生成代码”(可能是后端)就会一起完成。

您可以通过使用Process Explorer观看cl.exe来确认这一点。

为什么一次为多个文件生成代码

我的猜测是一次完成多个文件的代码生成是为了使构建过程更快,因为它包含了一些只能为多个源执行一次的事情,比如实例化模板 - 它没有用来实例化它们多次,因为所有实例都会被丢弃。

整个计划优化

理论上,此时也可以执行一些交叉编译单元优化,但是没有完成 - 除非使用/ LTCG启用,否则不会进行此类优化,而使用LTCG,整个代码生成是一次完成整个程序(因此整个程序优化名称)。

注意:似乎WPO是由链接器完成的,因为它从obj文件生成exe,但这是一种错觉 - obj文件不是真正的目标文件,它们包含中间表示,并且“链接器”不是真正的链接器,因为它不仅链接现有代码,而且还生成和优化代码。

答案 1 :(得分:2)

既不是并行化也不是代码优化。

多个源文件的长“生成代码...”阶段将返回VC6。它独立于优化设置或可用CPU,即使在禁用优化的调试版本中也是如此。

我没有详细分析,但我的观察是:当在具有不同编译选项的单元之间切换时,或者当某些数量的代码通过“逐个文件”部分时,它们会发生。它也是VC6中大多数编译器崩​​溃的阶段。

猜测:我一直认为通过一次处理多个项目来改善“硬部分”,可能只是缓存中加载的代码和数据。另一种可能性是单步阶段就像疯了一样占据记忆,而“生成代码”则释放出来。

提高构建性能:

购买你能买得起的最好的机器
这是您可以做出的最快,最便宜的改进。 (除非你已经有一个)。 转移到Windows 7 x64,购买大量RAM,以及i7 860或类似产品。 (从Core2双核移动给我一个6..8的因子,建立在所有CPU上。)

(也不要在磁盘上便宜。)

拆分为并行构建的单独项目
这是带有大量RAM的8 CPUS(即使4个物理+ HT)。您可以使用/MP选项启用每个项目的并行化,但这与许多其他功能不兼容。

答案 2 :(得分:1)

一次编译意味着解析源代码并生成代码。现在,编译意味着解析源并构建代表代码的符号数据库。然后可以将数据库转换为符号之间的已解析引用。稍后,数据库将用作生成代码的源。

您尚未启用优化功能。这将阻止构建过程优化生成的代码(或者至少暗示不应该进行优化......我不想保证不执行优化)。但是,构建过程仍然是优化的。因此,多个.cpp文件正在一起批处理。

我不确定如何决定将多少个.cpp文件一起批处理。也许编译器开始处理文件,直到它决定数据库的内存大小足够大,这样如果它再次增长,系统将不得不开始对磁盘进出过多的数据分页以及批量处理的性能提升。 cpp文件将被否定。

无论如何,我不为VC编译团队工作,所以无法最终回答,但我一直认为它是出于这个原因。

答案 3 :(得分:0)

在Visual C ++博客上有一篇新的文章详细介绍了一些未记录的开关,这些开关可用于计时/描述构建过程的各个阶段(我不确定写入的内容有多少,如果有的话)适用于VS2010之前的MSVC版本。有趣的东西应该提供至少一点洞察幕后发生的事情:

如果不出意外,它会让您知道哪些进程,dll以及至少一些翻译/处理阶段与您在正常构建输出中看到的消息相对应。

答案 4 :(得分:-1)

如果你有一个多核CPU

,它会对构建(或至少是编译)进行并行化

编辑:我很确定它与“make -j”相同并行化,它同时编译多个cpp文件(因为cpp通常是独立的) - 但显然将它们链接一次。
在我的core-2机器上,它在编译单个项目时显示了2个devenv作业。