如何通过预编译头文件(PCH 文件)优化编译时间






4.89/5 (6投票s)
您是否好奇预编译头文件(或 .pch 文件)究竟是什么,以及为什么要使用它们?本文将介绍这些内容,并提供一个如何使用它们的示例。
点击此处免费下载 IncrediBuild,加速您的 C++ 开发.
什么是头文件?
如果您问这个问题,那么您很可能刚接触 C 和 C++(老实说,快速复习一下总没坏处。)
头文件(.h 扩展名)在 C 和 C++ 中用于定义函数、模板和宏的结构,这些结构可以包含在一个或多个源文件中。这个概念是在 20 世纪 70 年代引入的,当时仅加载头文件是节省宝贵内存和其他系统资源的一种方式。
当然,自 20 世纪 70 年代以来,我们已经走了很长一段路,而且在大多数系统上,内存可能不再是如此稀缺的商品。但尽可能精简高效总是好的,而头文件在实现这一目标方面发挥着重要作用。
世界上最著名的头文件是 stdio.h,它位于为 C 编写的每个“hello world”示例应用程序的顶部,其中包括将文本写入控制台的实际 printf 函数的结构。
$ cat hello-world.c #include <stdio.h> int main() { printf("Hello World\n"); return 0; }
什么是预编译头文件?
预编译头文件的名称表明了它的含义。在 C/C++ 应用程序的编译过程中,编译头文件的步骤已经完成。拥有已经编译好的头文件可以显著减少编译时间。
预编译头文件如何工作?
预编译头文件的工作原理是保留上次运行时编译的头文件。 第一次编译项目时,如果您已配置为支持预编译头文件,则编译器和支持工具(如 nmake 或 ant)将编译头文件并生成 PCH 文件。
第二次和后续时间运行编译器时,它会将头文件与上次编译的内容进行比较,如果没有任何更改,它将使用预编译头文件。这就是为什么提前正确地构建头文件,并拥有一个相对稳定的代码库,才能真正发挥这种性能增强方法的优势。
在流行的编译器上启用预编译头文件
如果您正在使用 Visual Studio 并且有兴趣启用预编译头文件,请阅读 MSDN 上关于该主题的文档。
GCC 也有关于启用预编译头文件的文档。
如果您更喜欢 Intel 的编译器,它也完全支持预编译头文件。
使用预编译头文件可以带来的时间差异示例
让我们创建一个非常简单的程序。
$ cat header.h #include <CoreFoundation/CoreFoundation.h> #include <objc/objc.h> #include <objc/objc-runtime.h> #include <iostream> $ cat simple.cpp #include "header.h" int main() { return 0; }
并记录编译时间
$ time g++ -std=c++11 simple.cpp -o simple real 0m1.152s user 0m0.424s sys 0m0.585s
现在让我们预编译头文件,然后重新编译以记录时间
$ g++ -std=c++11 header.h $ time g++ -std=c++11 simple.cpp -o simple real 0m0.601s user 0m0.411s sys 0m0.149s
注意到区别了吗?它节省了半秒钟。现在想象一下大规模情况下的差异。
结论和额外的编译时间优化
对于任何代码库来说,预编译头文件都是减少应用程序编译时间的绝佳第一步——最大的一个需要注意的是,应用程序代码库需要进行结构化,才能真正利用它。启用预编译头文件并非万能药,但它通常会有一些帮助——并且通过一些努力或预先规划,可以提供很大的帮助。(如果您想了解更多背景信息,可以查看支持和反对预编译头文件的论点。)
如果您想进一步缩短编译时间,或者有一个特别复杂的项目,在开始时没有考虑预编译头文件,比如 Xbox 游戏,那么您可以采取其他步骤。其中最重要的一步是大规模并行化您的编译过程。从桌面上的四个核心到服务器场上的 400 甚至更多核心,总不会有坏处,对吧?诀窍在于拥有可用的服务器容量,并拥有适当的流程和工具来管理构建,以便所有内容仍然以正确的顺序完成,并在最后正确组装。
这就是 IncrediBuild 等公司发挥作用的地方。他们提供的服务从可以集成到 IDE 中的插件开始,支持预编译头文件,协助测试自动化,并提供具有您所需容量的云服务,以使您的编译更具时间效率。他们已经看到了高达 90% 的编译时间缩短。