对于我的小型(5-6000行代码)C程序,我使用了VS 2015和2017,我的构建时间在第一次构建时大约2分钟.这显然非常慢,但我不确定为什么.在工具 – >选项 – >项目和解决方案 – >构建和运行 – 我已经将“最大并行项目构建数”设置为8,但没有发生任何变化.
是否有任何其他设置或一般规则可用于缩短构建时间?
解决方法:
编译需要时间……这是一个复杂的过程,尤其是在包含许多文件和项目的大型解决方案中.
但是有些东西可以减少Visual Studio的编译时间.
使用好的硬件.
具有足够空闲空间,良好的多核处理器和足够RAM的SSD始终是更快编译的良好基础.
使用预编译标题
预编译头可以大大加快构建过程.如果在项目创建期间没有自动创建它们,则设置起来有点复杂,但在许多情况下绝对值得付出努力.
以下是如何打开它们:
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.
pch.cpp只包含一行:
#include "pch.h"
它有一个特殊的目的(见下文).
现在将#include“pch.h”添加到项目中的每个cpp,位于cpp文件的VERY TOP位置.这对于预编译的头文件是必需的.
接下来是在项目中启用预编译的头文件.
打开项目属性,并输入所有配置和所有平台,他们应该“使用”预编译的头文件:
这告诉项目您要将pch.h用作预编译头文件.
最后一步是将pch.cpp的文件属性更改为“create”(这是特殊用途):
这意味着pch.cpp将从现在开始创建Visual Studio所需的二进制预编译头文件.
拆分项目并保持良好的项目层次结构.
通常,将所有内容放在一个大型项目中并从每个文件中调用每个文件都不是一个好主意,既不是编译时也不是设计.
您应该将解决方案拆分为某个“级别”的静态库.
最低级别可以是例如是一个基本的网络库,IO库,包装器,标准改进,便利助手等.
中等水平可以是例如一个专门的线程库(使用较低级别,如网络,IO等)
*别是您的申请.
较高级别可以访问较低级别(最好是直接在下面的级别),但较低级别永远不能访问较高级别(除非通过接口,如果需要).
这可以确保 – 在您处理应用程序时 – 只需要重建应用程序,而不是整个项目.
避免不必要的Header-Only-Classes.
当然你需要只有标题的类,例如STL.而且模板只能在header-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();
};
}
并且您希望将此类的引用或(智能)指针存储在更高级别的类头中:
#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
};
}
当然这是有效的代码,但编译可能会很慢. 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
};
}
无需包含整个标题!由于m_helperRef不是一个完整的实例化类对象,而只是一个智能指针,并且该智能指针仅用于CPP,因此标头不需要知道MySuperHelper究竟是什么,它只需要一个前向声明.只有CPP – 它直接实例化和使用MySuperHelper – 需要确切地知道它是什么,因此必须#include“lowlevel.h”这可以加快编译速度.一个图书馆/引擎,做得非常好,是Ogre;如果您#include< ogre.h>,您将只包含一个前向声明列表,可以快速编译.如果您想使用Ogre的类,那么您可以在CPP中包含特定的标题.
使用多核并行编译
就像我说的,编译是一个非常复杂的过程,我不得不承认我对如何改进并行编译的秘密不太了解(可能是其他人可以提供帮助).在许多情况下,编译是依赖性的顺序过程.尽管如此,某些情况可以在没有更深入了解的情况下并行编译,Visual Studio有一些选项可以这样做.
在工具/选项/构建和运行下,您可以输入要同时构建的最大项目数.
但这些只是并行构建的项目.项目本身仍将按顺序编译.但是这也可以在项目本身的项目设置中进行更改(您必须为每个项目执行此操作)
然而,不要指望并行编译有任何奇迹.还有很多案例需要按顺序处理.
分析您的标题包含
您可以打开“显示包含”,它将为您提供构建输出中包含的头文件的列表:
(当然这个功能应该只是暂时打开,因为它会极大地减慢构建过程 – 这与你想要的相反;))
在构建之后,您可以分析输出,或者找到一些您可以删除的不必要的标头.
AFAIK也有一些工具,可以自动为你做,但还没有尝试过. Here是一篇帖子,其中指出ReSharper C++提供了删除未使用标头的功能(这也是我尚未尝试过的)
禁用构建文件夹的病毒扫描程序
在构建期间,将创建大量文件.如果病毒扫描程序在构建期间访问这些文件,则可能导致严重减速.从病毒扫描程序访问中排除至少临时构建文件夹.