预编译头失效主因是编译器未将其识别为pch:msvc要求源文件首行非空非注释必须为#include "stdafx.h",clang/gcc需正确配合-include与-x c++-header参数且禁止前置包含。

为什么你的 stdafx.h 或 xxx_PCH.h 没起作用?
预编译头失效,八成是因为编译器根本没把它当 PCH 用——不是加了头文件就自动加速。MSVC 要求源文件必须以 #include "stdafx.h"(或你指定的 PCH 头)作为**第一个非空、非注释行**;Clang/GCC 则依赖 -include 和 -x c++-header 配合,且源文件不能提前包含其他头。一旦 #include <vector></vector> 出现在 PCH 之前,整个预编译流程就退化为普通编译。
- VS 项目里检查「属性 → C/C++ → 预编译头」是否设为「使用预编译头(
/Yu)」,且「预编译头文件」填的是你实际 include 的路径(如stdafx.h),不是生成的stdafx.pch - Clang/GCC 下,必须显式用
-include pch.h -x c++-header pch.h -o pch.pch生成,再在编译源码时加-include pch.h,且不能带-x c++-header(否则会误把源文件当头处理) - 常见错误:在 PCH 头里写了
using namespace std;——这会让所有包含它的源文件都污染命名空间,后期重构极痛苦
#include <boost></boost> 这类重型头该不该放进 PCH?
该,但得卡住边界:只放**稳定、高频、不常改**的系统头和基础库头。Boost.Asio 本身依赖多、模板深,放进 PCH 后,只要它任意一个间接依赖头(比如 boost/system/error_code.hpp)变了,整个 PCH 就要重做——反而拖慢日常迭代。真正适合塞进去的是 <string></string>、<memory></memory>、<unordered_map></unordered_map>、Qt 的 <qobject></qobject> 等项目里每个 cpp 都用、且版本锁死的头。
- 用
cl /showIncludes(MSVC)或clang++ -H查看单个 .cpp 的头包含树,挑出前 10 层里重复出现 ≥5 次的头 - 避免放入含宏定义的头(如
WIN32_LEAN_AND_MEAN相关头),因为不同源文件可能需要不同宏组合,PCH 会强制统一 - 如果用了模块(C++20
import),PCH 和模块不能混用——编译器会直接报错error C7613: #include after module import
Clang 的 -fmodules 和 PCH 哪个更快?
模块快,但迁移成本高;PCH 粗糙但见效快。Clang 模块对 <vector></vector> 这类标准库头做了二进制缓存,解析一次后复用,比 PCH 的文本展开更轻量。但要求所有依赖库提供 modulemap,而现实里 90% 的第三方库(包括多数 Boost 组件)根本不支持。你强行用 -fmodules -fimplicit-modules,遇到 #include "third_party.h" 就会 fallback 到传统模式,PCH 反而更可控。
- 实测:纯 STL + Qt 项目,PCH 编译提速 30–40%,Clang modules 在完整启用时可达 50%+,但需手动写 modulemap、禁用宏干扰、并接受构建系统改造
- Clang PCH 文件(.pch)默认不压缩,磁盘占用大;可用
-Xclang -fno-pch-timestamp关闭时间戳校验,避免因头文件 mtime 变动导致无谓重建 - 注意
-fprebuilt-module-path路径必须绝对,相对路径在 Ninja 构建下容易失效
为什么改了一个 .h 文件,所有 .cpp 还是全量重编?
PCH 只加速头文件解析阶段,不解决依赖传播问题。如果你在公共头 common.h 里改了一个内联函数,所有 #include "common.h" 的 .cpp 仍要重编——因为目标文件的符号定义变了。PCH 的价值是让每个 .cpp 在「解析 <string></string>、<memory></memory>…」这段耗时操作变成毫秒级内存加载,而不是秒级重新 lex&parse。
立即学习“C++免费学习笔记(深入)”;
- 真正的增量瓶颈往往在头依赖设计:用前向声明替代
#include,把class WidgetImpl;放头文件,#include "widget_impl.h"移到 .cpp 里 - 检查构建日志里是否有
skipping precompiled header(MSVC)或not using precompiled header(Clang),这是 PCH 被跳过的明确信号 - 大型项目中,PCH 文件本身可能超 200MB,SSD 读取快,但 CI 环境若用 HDD 或网络文件系统,加载 PCH 反而成为新瓶颈
最麻烦的从来不是怎么配 PCH,而是判断哪些头值得放进它、哪些改动看似微小却会触发整条依赖链重编。盯紧 #include 树和构建日志里的「skipping」提示,比调参数重要得多。










