如何为c++项目配置预编译头文件(PCH)以加快编译速度? (CMake/VS设置)

12次阅读

预编译头文件(PCH)能显著缩短大型c++项目编译时间,但需正确配置:VS中须为每个.cpp手动设/Yu并确保首行#include “pch.h”;CMake需按编译器分别处理,MSVC用target_precompile_headers()配合add_compile_options(“$”),Clang需确保pch.h在include路径中;GCC不建议使用;PCH头须稳定、禁含宏/模板/条件编译;验证需检查/showincludes输出及cl.exe参数是否含/Yu和/Fp。

如何为c++项目配置预编译头文件(PCH)以加快编译速度? (CMake/VS设置)

预编译头文件(PCH)在大型 C++ 项目中确实能显著缩短编译时间,但效果高度依赖配置方式——stdafx.hpch.h 本身不加速,错误的包含顺序、不一致的编译选项或未被所有源文件使用,反而会让构建更慢甚至失败。

VS 中启用 PCH 需手动设置每个源文件的“预编译头”属性

visual studio 不会自动将 pch.h 应用到所有 .cpp 文件。即使你在项目属性里启用了“创建/使用预编译头”,每个 .cpp 文件仍需单独设置:

  • 右键 .cpp 文件 → “属性” → “C/C++” → “预编译头” → 选择 使用预编译头(/Yu)
  • 确保该文件**第一行**是 #include "pch.h"(或你命名的 PCH 头),且前面不能有任何非注释内容(包括 #pragma once、宏定义、空行都不行)
  • 若某文件不想用 PCH(如生成器脚本、第三方封装层),则设为 不使用预编译头(/Y-),否则会报错 C1010: 在查找预编译头时遇到意外的文件结尾

CMake 中配置 PCH 必须区分编译器且显式指定头路径

CMake 本身不原生支持 PCH,需通过编译器特定方式注入。对 MSVC 和 Clang/LLVM 处理完全不同:

  • MSVC:用 target_precompile_headers()(CMake 3.16+),但必须配合 add_compile_options("$:/Yupch.h>") 才生效
  • Clang/LLVM(含 macOS xcode):需用 target_precompile_headers(my_target private "pch.h"),且要求 pch.htarget_include_directories() 路径下可找到
  • GCC 不支持标准 PCH 注入(仅支持 -include,但无法跳过头文件解析,几乎无加速效果),不建议在 GCC 项目中强行配 PCH
target_precompile_headers(mylib PRIVATE "pch.h") target_include_directories(mylib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) # 注意:pch.h 必须能被 #include "pch.h" 直接找到,否则报 C1083

PCH 头文件内容必须稳定,且禁止含宏/模板/条件编译

一旦 PCH 编译完成,其二进制缓存(如 pch.pchpch.h.gch)就固定了。以下写法会导致隐性失效或编译错误

立即学习C++免费学习笔记(深入)”;

  • pch.h#include 后又 #define _HAS_CXX17 0 —— 宏定义顺序冲突,可能触发 C2857
  • pch.htemplate Struct wrapper { ... }; —— 模板实例化延迟,PCH 缓存不包含具体实例,实际编译仍要展开
  • #ifdef DEBUG 包裹标准库头 —— 构建类型切换(Debug/Release)时 PCH 缓存不可复用,CMake 会强制重建整个 PCH

验证 PCH 是否真正生效的关键指标

别只看“有没有生成 pch.pch”,要确认它被实际使用:

  • 编译单个 .cpp 文件时加 /showIncludes(MSVC)或 -H(Clang),输出首行应为 Note: including file: ...pch.h,且后续系统头不再逐行列出
  • 对比开启前后 cl.exe 的调用参数:有 PCH 时应含 /Yu"pch.h" /Fp"Debugmyproj.pch";无 PCH 时只有 /FI"pch.h"(这是强制包含,不加速)
  • 修改 pch.h 后,所有依赖它的 .cpp 文件必须全部重编译——如果只有部分重编,说明某些文件没正确启用 /Yu

最常被忽略的一点:PCH 加速效果在增量编译中并不线性。改一个业务头文件,可能只触发 3 个 .cpp 重编;但改 pch.h,会触发全部重编。所以 PCH 头越稳定、越少变更,长期收益越大——把它当成“只读的底层契约”,而不是“方便塞一 include 的垃圾桶”。

text=ZqhQzanResources