构建时间:Visual Studio 2015-2017构建非常慢

Jas*_*son 4 c++ msbuild build build-time visual-studio

对于我的小型(5-6000行代码)C++程序,我使用了VS 2015和2017,我的构建时间在第一次构建时大约是2分钟.这显然非常慢,但我不确定为什么.在tools-> options-> projects and solutions-> build and run中 - 我已经将"最大并行项目构建数"设置为8但没有发生变化.

是否有任何其他设置或一般规则可用于缩短构建时间?

use*_*447 10

编译需要时间......这是一个复杂的过程,尤其是在包含许多文件和项目的大型解决方案中.但是有些东西可以减少Visual Studio的编译时间.

使用好的硬件.

具有足够空闲空间,良好的多核处理器和足够RAM的SSD始终是更快编译的良好基础.

使用预编译标题

预编译头可以大大加快构建过程.如果在项目创建期间没有自动创建它们,则设置起来有点复杂,但在许多情况下它绝对值得付出努力.以下是如何打开它们:

您的项目中需要两个文件,例如pch.h和pch.cpp. 在此输入图像描述

pch.h包含您希望在项目中常用的所有定义和标题

#ifdef _WIN32
#   define _WIN32_WINNT                 0x0502    
#   define WIN32_LEAN_AND_MEAN
#   define VC_EXTRALEAN
#   define NOMINMAX
#endif
#include <windows.h>  

#define OIS_DYNAMIC_LIB
#include "OgreVector3.h"

#include <string>
#include <vector>
etc. pp.
Run Code Online (Sandbox Code Playgroud)

pch.cpp只包含一行:

#include "pch.h"
Run Code Online (Sandbox Code Playgroud)

它有一个特殊的目的(见下文).

现在#include "pch.h"在您的项目中,在cpp文件的VERY TOP位置添加一个到每个cpp.这对于预编译的头文件是必需的.

接下来是在项目中启用预编译的头文件.打开项目属性,并输入所有配置和所有平台,他们应该"使用"预编译的头文件:

在此输入图像描述

这告诉项目您要将pch.h用作预编译头文件.

最后一步是将pch.cpp的文件属性更改为"create"(这是特殊用途): 在此输入图像描述

这意味着pch.cpp将从现在开始创建Visual Studio所需的二进制预编译头文件.

拆分项目并保持良好的项目层次结构.

通常,将所有内容放在一个大型项目中并从每个文件中调用每个文件都不是一个好主意,既不是编译时也不是设计.您应该将解决方案拆分为某个"级别"的静态库.

最低级别可以是例如基本网络库,IO库,包装器,标准改进,便利助手等.

中等级别可以是例如专用的线程库(使用较低级别,如网络,IO等)

最高级别是您的申请.

较高级别可以访问较低级别(最好是直接在下面的级别),但较低级别永远不能访问较高级别(除非通过接口,如果需要).这可以确保 - 在您处理应用程序时 - 只需要重建应用程序,而不是整个项目.

避免不必要的Header-Only-Classes.

当然,您需要仅限标题的类,例如STL.而且模板只能在he​​ader-only-classes中使用.但是如果你正在编写一个非模板类,它应该经典地分成cpp和header来改善编译时间.此外,只应在标题中实现简短方法(例如,普通的getter和setter).

避免不必要的包含,改为使用前向声明

假设您在较低级别的标题中有一个类:

#include "my_template_lib_which_takes_ages_to_compile.h"

namespace LowLevel {
  class MySuperHelper {
    my_template<int> m_bla;
  public:
    MySuperHelper();
    virtual ~MySuperHelper();
    void doSomething();
  };
}
Run Code Online (Sandbox Code Playgroud)

并且您希望将此类的引用或(智能)指针存储在更高级别的类头中:

#include "lowlevel.h"

namespace MediumLevel {
  class MyMediumClass {
    std::unique_ptr<LowLevel::MySuperHelper> m_helperRef;
  public:
    MyMediumClass(); //constructor initializes the smart pointer in cpp
    virtual ~MyMediumClass();
    void work(); // works with the smart pointer in cpp
  };
}
Run Code Online (Sandbox Code Playgroud)

当然这是有效的代码,但编译可能会很慢.MySuperHelper使用慢速编译模板lib来实例化其成员,从而包含其标题.如果现在包含lowlevel.h,则还将包含慢速模板库.如果更高的类包含您的中类标题,它将包括中级标题,低级标题和模板标题......等等.

你可以通过前向声明来避免这种情况.

namespace LowLevel {
  class MySuperHelper;
}

namespace MyMediumLevel {
  class MyMediumClass {
    std::unique_ptr<LowLevel::MySuperHelper> m_helperRef;
  public:
    MyMediumClass(); //constructor initializes the smart pointer in cpp
    virtual ~MyMediumClass();
    void work(); // works with the smart pointer in cpp
  };
}
Run Code Online (Sandbox Code Playgroud)

无需包含整个标题!由于m_helperRef不是一个完整的实例化类对象,而只是一个智能指针,并且该智能指针仅用于CPP,因此标头不需要知道MySuperHelper究竟是什么,它只需要一个前向声明.只有CPP - 直接实例化和使用MySuperHelper--需要确切地知道它是什么,因此必须#include "lowlevel.h"这样可以加快编译速度.一个图书馆/引擎,这是非常好的,是食人魔 ; 如果您#include <ogre.h>,您将只包含一个前向声明列表,可以快速编译.如果您想使用Ogre的类,那么您可以在CPP中包含特定的标题.

使用多核并行编译

就像我说的,编译是一个非常复杂的过程,我不得不承认我对如何改进并行编译的秘密不太了解(可能是其他人可以提供帮助).在许多情况下,编译是依赖性的顺序过程.尽管如此,某些情况可以在没有更深入了解的情况下并行编译,Visual Studio有一些选项可以这样做.

Tools/Options/Build and Run您可以输入项目的最大数量的并发建设. 在此输入图像描述

但这些只是并行构建的项目.项目本身仍将按顺序编译.但是这也可以在项目本身的项目设置中进行更改(您必须为每个项目执行此操作)

在此输入图像描述

然而,不要指望并行编译有任何奇迹.还有很多案例需要按顺序处理.

分析您的标题包含

您可以打开"显示包含",它将为您提供构建输出中包含的头文件的列表: 在此输入图像描述 (当然这个功能应该只是暂时打开,因为它极大地减慢了构建过程 - 这与你想要的相反;)在构建之后你可以分析输出并找到一些你可以删除的不必要的头文件.AFAIK也有一些工具,可以自动为你做,但还没有尝试过.这里的其中规定后ReSharper的C++提供了一个功能,删除未使用的标题(这也是我还没试过)

禁用构建文件夹的病毒扫描程序

在构建期间,将创建大量文件.如果病毒扫描程序在构建期间访问这些文件,则可能导致严重减速.从病毒扫描程序访问中排除至少临时构建文件夹.

  • 哇,好极了。非常感谢您的见解和努力。我认为您几乎涵盖了构建时间缓慢的所有原因,这应该得到更多的支持。最后,设置/ MP选项以利用更多的内核确实可以解决问题(从构建时间中节省一分钟),并且实现了我尝试使用“最大并行项目构建数”选项(现在我意识到与利用更多内核无关)。 (2认同)
  • 谢谢,很高兴能为您提供帮助:)确实,“最大并行项目构建数量”确实使用了更多的内核-但前提是您的解决方案中有很多项目。/ MP更强大。 (2认同)