编译需要时间...这是一个复杂的过程,尤其是在包含许多文件和项目的大型解决方案中。
但是有些事情可以减少Visual Studio上的编译时间。
使用优质的硬件。
具有足够的可用空间,良好的多核处理器和足够的RAM的SSD始终是快速编译的良好基础。
使用预编译头
预编译的头文件可以大大加快构建过程。如果在项目创建期间未自动创建它们,则设置起来会有些复杂,但是在许多情况下绝对值得付出努力。
开启方法如下:
您的项目中将需要两个文件,例如pch.h和pch.cpp。
pch.h包含您要在项目中常用的所有定义和 header 。
#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文件的非常顶部位置。对于预编译的头文件,这是必需的。
下一步是在项目中启用预编译的头文件。
打开您的项目属性,并为所有配置和所有平台输入它们应“使用”预编译的头文件:
这告诉项目您要使用pch.h作为预编译的头文件。
最后一步是将pch.cpp的文件属性更改为“创建”(这是特殊目的):
这意味着pch.cpp从现在开始将创建Visual Studio需要的二进制预编译头文件。
拆分项目并保持良好的项目层次结构。
通常,将所有内容放在一个大型项目中并从每个文件中调用每个文件(不是编译时还是设计时)都不是一个好主意。
您应该将解决方案拆分为某个“级别”的静态库。
最低级别例如成为基本的网络库,IO库,包装器,std改进,便利工具等。
中等水平可以是例如专门的线程库(利用网络,IO等较低级别的资源)
最高级别将是您的应用程序。
较高的级别可以访问较低的级别(最好是直接位于下面的级别),但是较低的级别永远不能访问较高的级别(必要时通过接口(interface)除外)。
这样可以确保-在您处理应用程序时-只需重新构建应用程序,而不必重新构建整个项目。
避免不必要的仅 header 类。
当然,您需要仅 header 的类,例如STL。而且模板仅在仅 header 类中可用。
但是,如果您要编写非模板类,则应将其经典地分为cpp和 header ,以缩短编译时间。此外, header 中仅应实现简短的方法(例如琐碎的getter和setter)。
避免不必要的包含,请改用转发声明
假设您在较低级别的 header 中有一个类:
#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使用慢速编译模板库来实例化其成员,因此包括其 header 。如果现在包括lowlevel.h,则还将包括慢速模板库。而且,如果较高的类别包含您的中级类别 header ,则它将包含中级 header ,低级 header 和模板 header ……等等。
您可以使用前向声明避免这种情况。
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中使用,所以 header 不需要知道MySuperHelper到底是什么,它只需要一个前向声明。只有CPP(直接实例化MySuperHelper并与MySuperHelper一起使用)才需要确切地知道它是什么,因此需要
#include "lowlevel.h"
。这可以大大加快编译速度。一个很好的库/引擎是
Ogre;如果您使用
#include <ogre.h>
,则将仅包含一个前向声明列表,该列表可以快速编译。如果要使用Ogre的类,则可以在CPP中包含特定的 header 。
使用多核并行编译
就像我说的那样,编译是一个非常复杂的过程,我不得不承认,我在改善并行编译方面的 secret 不是很好(可能有人可以提供帮助)。在许多情况下,编译是依序的依存过程。但是,某些情况下可以在没有更深入的知识的情况下并行编译,Visual Studio有一些选择可以这样做。
在
Tools/Options/Build and Run
下,您可以输入要同时构建的最大项目数。
但是,这些只是并行构建的项目。项目本身仍将按顺序编译。但这也可以在项目本身的项目设置中更改(您必须对每个项目都执行此操作)
但是,不要期望并行编译会带来任何奇迹。仍然有很多情况需要顺序处理。
分析您的 header 包含
您可以打开“显示包含”,这将为您提供构建输出中包含的头文件的列表:
(当然,此功能只能暂时打开,因为它会极大地减慢构建过程的速度,这与您想要的相反;)
构建完成后,您可以分析输出,并找到一些可以删除的不必要的 header 。
AFAIK还提供了一些工具,可以自动为您完成此操作,但还没有自己尝试过。
Here的帖子指出
ReSharper C++提供了删除未使用的 header 的功能(也是我尚未尝试过的功能)
对构建文件夹禁用病毒扫描程序
在构建期间,将创建大量文件。如果病毒扫描程序在构建过程中访问了这些文件,则可能导致严重的速度下降。从病毒扫描程序访问中至少排除临时生成文件夹。
我是一名优秀的程序员,十分优秀!