预编译头

预编译头（precompiled header）是程序设计时把头文件编译为中间格式（如目标文件），以节约在开发过程中编译器反复编译该头文件的开销。 C语言、C++语言、Objective C语言等都有类似的技术。 有的头文件包含了巨量的源代码（如著名的windows.h），或者使用模板编程时要生成巨大的头文件模板库（如Eigen math library（英语：List of numerical libraries）与Boost C++ libraries（英语：Boost C++ libraries）)。为减少编译时间，某些编译器允许把头文件编译为某种中间形式称为预编译头（precompiled header），后续再编译源文件时就可以尽量直接使用这些预编译头。 C++文件source.cpp包括header.hpp： //header.hpp ... //source.cpp #include "header.hpp" ... 首次编译source.cpp时，编译器生成header.pch的预编译头。以后再编译该程序时，编译器会比较该头文件的时间戳，如果头文件没有改变，编译器直接使用预编译头。 Microsoft Visual Studio采取一个头文件（默认命名为stdafx.h），其内容是整个软件项目中被各个编译单元所使用的源代码，并极少修改。每个编译单元的源代码从最开始之处直至#include "stdafx.h"的内容完全相同。其中一个编译单元（源文件默认命名为"stdafx.cpp"）以#include "stdafx.h"为最后一行（不考虑程序注释），并用编译选项/Yc"stdafx.h"编译，这将生成预编译头（默认命名为"<项目名>.pch"）,包含了到#include "stdafx.h"这一行为止的所有代码编译结果。 项目中的其他编译单元，使用/Yu"stdafx.h"编译，这将把从开头直至#include "stdafx.h"这一行的源代码跳过编译过程，直接用预编译头（默认命名为"<项目名>.pch"）代替。 stdafx中的AFX代表Application Framework eXtensions。AFX是Microsoft Foundation Classes (MFC)的旧称。编程者也可以用其他名字的头文件代替stdafx.h。 Visual Studio编译器确定预编译头的文件名，依照下述次序： 编译器选项/Fp中给出的参数； 源文件中预处理器指令#pragma hdrstop [( "filename" )]给出的预编译头的文件名。源文件从开始之处至该行#pragma hdrstop的内容，用于创建预编译头（若使用/Yc选项）或者被预编译头取代（若使用/Yu选项）。 /Yu"头文件基名.h"中的文件的base name加上后缀.PCH； 当前源文件的的base name加上后缀.PCH。 GCC3.4版开始支持预编译头。当编译器输入文件为头文件时（例如sample.h），产生预编译头，其文件名称是原来的头文件追加".gch"后缀（如sample.h.gch）。当gcc编译源文件时，对于遇到的每个头文件，都在INCLUDE路径中的每个目录下，先搜寻追加".gch"后缀的预编译头，如果没有再搜索该头文件。如果找到预编译头且满足一些条件，则直接使用该预编译头；否则就把该头文件在源文件中展开并编译之。 可以在编译源文件时使用-H选项，如果显示的预编译头的全路径这一行是以"!"开始，说明编译器成功使用了预编译头；如果这一行以"x"开始，说明编译器找到了这一预编译头但未能使用它。 gcc对C语言的头文件与C++的头文件产生的格式不同，不能混用。如果头文件的名字不是".h"或".hpp"后缀结尾（C++标准库的头文件基本如此），可以用编译选项-x c++-header让gcc把当前的输入文件当作C++头文件来处理。用编译选项-x c-header让gcc把当前的输入文件当作C头文件来处理。 使用预编译头时必须满足下列条件： 编译一个源文件，至多只能使用一个预编译头。 编译源文件时，如果先于预编译头对应的头文件编译器就扫描到C/C++的词（token），则不能使用该预编译头。也就是说，在预编译头对应的头文件之前的源文件中，只能有预处理指令（preprocessor directive)。 不能在另一个头文件中引入使用预编译头。 预编译头与源文件必须是相同语言。不能在编译C++源文件时使用C语言的预编译头。 预编译头与源文件应当由同一个编译器编译。以保证二进制兼容。 在预编译头之前定义的宏（macro）或者被引入源程序时与预编译头生产时完全一致，或者预编译头没有用到该宏。这包括了由编译选项-D定义的宏、#define定义的宏、以及某些编译选项如-O或-Wdeprecated隐式定义的宏。 源文件用-g选项编译以获取调试信息时，其使用的预编译头也应该是用-g编译选项生成的。但是，用-g选项编译生成的预编译头，也可用在没有调试信息输出的源文件编译。 生成与使用预编译头，必须使用相同的-m选项。该编译选项给出目标硬件平台的相关信息。 生成与使用预编译头，必须使用相同的-fexceptions选项。 生成与使用预编译头，必须使用以-f, -p, -O开头的相同的命令行选项。目前还不知道哪些编译选项可以安全地改变或者决不能改变，最安全的选择是生成与使用预编译头使用相同的编译选项。已知下述选项可以安全地改变： -fmessage-length= -fpreprocessed -fsched-interblock -fsched-spec -fsched-spec-load -fsched-spec-load-dangerous -fsched-verbose=number -fschedule-insns -fvisibility= -pedantic-errors 上述条件如果不被满足，编译器将自动使用头文件而不是对应的预编译头。 在项目默认配置中，C++Builder编译器无保留地生成在#pragma hdrstop之前所有头文件的预编译头。如果可能的话，预编译头会被项目的所有模块共享。例如，当使用Visual Component Library时，通常首先会包含vcl.h头文件，该头文件含有大多数经常被用到的VCL头文件。因此，预编译头被全项目共享可以显著减少生成时间。 另外，C++Builder能设置为使用一个特定的头文件作为预编译头，和Visual C++提供的机制类似。 C++Builder 2009引入了“Precompiled Header Wizard（预编译头向导）”来为被包含的头文件提取所有源码，然后自动为特定的文件分类（例如排除那些不是项目成员或者没有Include防范的头文件）、生成并测试预编译头。 The Care and Feeding of Pre-Compiled Headers （页面存档备份，存于互联网档案馆） Precompiled Headers with GCC Fractal eXtreme: Precompiled headers （页面存档备份，存于互联网档案馆） MSDN Help Document: hdrstop. [2015-06-07]. （原始内容存档于2018-09-24）.  GCC online documentation §3.20: Using Precompiled Headers. [2015-06-07]. （原始内容存档于2015-09-18）.  GCC online documentation §3.2 Options Controlling the Kind of Output. [2015-06-07]. （原始内容存档于2015-09-18）.