【问题标题】:How to optimize building speed in visual studio 2008如何在 Visual Studio 2008 中优化构建速度
【发布时间】:2011-05-25 04:15:48
【问题描述】:

有人可以给我提示以提高 Visual Studio 2008 中的构建速度吗?
我有一个大型项目,其中包含许多具有完整源代码的模块。每次构建时,都会重新构建每个文件,其中一些没有更改。我可以阻止这些文件被重建吗? 我打开了属性“启用最小重建”/Gm,但编译器抛出了这个警告

Command line warning D9030 : '/Gm' is incompatible with multiprocessing; ignoring /MP switch

每个提高构建速度的技巧都会对我有很大帮助。 谢谢,

【问题讨论】:

  • 你是说你 - 全部构建,什么都不做,然后重新构建所有东西会重新编译东西吗?
  • Xoreax Incredibuild 虽然不便宜,但有很大帮助。我们通常会获得超过 10 倍的加速。也就是说,损坏的依赖关系仍然会造成很大的伤害,因为它会强制进行昂贵的重新链接。

标签: c++ visual-studio-2008 compiler-construction build


【解决方案1】:

C++ 编译时间对于每个超过一定规模的项目来说都是一场战斗。幸运的是,有这么多人编写大型 C++ 项目,有多种解决方案:

经典的廉价解决方案是“统一构建”。这只是意味着使用#include 将所有 .cpp 文件放入单个文件中进行编译。 “Unity build”在stackoverflow 上出现了很多问题,here 是我所知道的最突出的问题。这个screencast 演示了如何在 Visual Studio 中设置这样的构建。

我的理解是统一构建比经典构建快得多,因为它们有效地缓存了预处理器和链接器完成的工作。统一构建的一个缺点是,如果您触摸一个 cpp 文件,您将不得不重新编译您的“大”cpp 文件。您可以通过将您正在迭代的 cpp 文件从统一构建中分离出来并自行编译来解决此问题。

在 Unity 构建之外,以下是我的最佳实践列表:

  • 仅在必要时使用#include,最好使用前向声明
  • 使用 pimpl 习惯用法将类实现排除在通常包含的头文件之外。这样做可以让您将成员添加到实现中,而无需进行长时间的重新编译
  • 对很少更改的常用头文件使用预编译头文件 (pch)
  • 确保您的构建系统使用本地硬件上的所有可用内核
  • 尽量减少预处理器必须搜索的目录列表,在#include 语句中使用精确路径
  • 在头文件的顶部使用#pragma once而不是#ifndef __FOO_H #define __FOO_H ... #endif,如果使用#ifndef技巧,编译器每次包含头文件时都必须打开它,#pragma once允许编译器更高效

如果您正在做所有这些(根据我的经验,统一构建将产生最大的影响),最后一个选项是分布式构建。 distcc 是我所知道的最好的免费解决方案,incredibuild 是专有的行业标准。我认为分布式计算将是从混乱的 C++ 编译过程中获得出色迭代时间的唯一方法。如果您可以访问相当多的机器(例如 10-20 台),这完全值得研究。我应该提到,统一构建和分布式构建并不是完全共生的,因为传统编译可以分成比统一构建更小的工作块。如果你想去分布式,可能不值得建立一个统一的构建。

【讨论】:

  • #pragma once 和 include guard 的顺序,我观察到(1)微软把#pragma放在include guard之后(2)即使#pragma在include guard之后,编译器也可以跳过打开文件.我的测试基于 VC2010+SP1,我使用 /showincludes 和 procmon 来调查此类问题。
【解决方案2】:

Enable Minimal Build:/GmBuild with Multiple Processes:/MP{<cores>} 不兼容
因此,您一次只能使用这两种中的一种。

/Gm > 项目属性:配置属性 > C/C++ > 代码生成

/MP{n} > 项目属性:配置属性 > C/C++ > 命令行


也为了防止不必要的构建(未触及的文件) - 构造你的代码正确;遵循这条规则:

在 [.h] 头文件中,仅将需要的部分放在头文件本身的内容旁边;
以及您需要在多个执行单元之间共享的所有内容。

其余部分在实施 [.c / .cpp] 文件中。

【讨论】:

  • 好的,但是这两个应该更喜欢哪一个?如果它们是互斥的,为什么微软没有简单地保留最好的呢?
【解决方案3】:

一个简单的方法是在调试模式下编译(也就是零优化),这当然只用于内部测试。

您还可以使用预编译的头文件*来加快处理速度,或将“不变”的段拆分为静态库,从重新编译中删除这些。

*对于/MP,你需要在多进程编译之前创建预编译头,因为/MP根据MSDN可以读不能写

【讨论】:

  • 根据我的经验,在调试模式下编译要慢得多,因为编写调试信息会产生更多的磁盘活动。
  • @fschmitt:你知道你可以在调试模式下编译并且让它不生成该信息,它(几乎)与在没有优化的版本中编译相同,无论哪种方式都完成了我的意思,删除昂贵的优化时间,它不会让其他任何点变得不那么真实......
【解决方案4】:

您能否提供有关您的项目结构以及正在重建哪些文件的更多信息?
未更改的 C++ 文件可能会被重建,因为它们包含已更改的头文件,在这种情况下 /Gm 选项将无济于事

【讨论】:

  • 我们的项目有一些外部开源项目。
【解决方案5】:

更改一个头文件后重新构建所有文件是一个常见问题。解决方案是仔细检查您的头文件使用的#include 并删除所有可以删除的内容。如果你的代码只使用类的指针和引用,你可以替换

#include "foo.h"

class Foo;

【讨论】:

    猜你喜欢
    • 2013-06-24
    • 2010-09-09
    • 2012-08-19
    • 2013-09-07
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    相关资源
    最近更新 更多