build-acceleration
构建加速(Build Acceleration)
用途
引导完成 C/C++ 构建时间的缩减:利用缓存(ccache/sccache)、分布式编译(distcc)、Unity/Jumbo 构建、预编译头(PCH)、用于加快链接的 Split-DWARF,以及通过 IWYU 裁剪头文件。
触发场景
- "我的 C++ 构建太慢,怎么加速?"
- "如何配置 ccache / sccache?"
- "预编译头如何在 CMake 中使用?"
- "如何使用 distcc 配置分布式编译?"
- "如何用 Split-DWARF 缩短链接时间?"
- "如何找出是哪些头文件拖慢了编译速度?"
工作流程
1. 先诊断瓶颈
# 计时完整构建
time cmake --build build -j$(nproc)
# 找出最慢的翻译单元(TU)(CMake ≥3.16 配合 --profiling-output)
cmake -S . -B build -DCMAKE_CXX_FLAGS="-ftime-report"
cmake --build build 2>&1 | grep "Total" | sort -t: -k2 -rn | head -20
# Ninja 构建计时(用 ninja -j1 串行计时)
ninja -C build -j1 2>&1 | grep "^\[" | sort -t" " -k2 -rn | head -20
2. ccache — 编译器缓存
# 安装
apt-get install ccache # Ubuntu/Debian
brew install ccache # macOS
# 查看命中率
ccache -s
# 配置缓存大小(默认 5GB)
ccache -M 20G
# 清空缓存
ccache -C
CMake 集成(推荐,优于前缀命令方式):
# CMakeLists.txt
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
endif()
~/.config/ccache/ccache.conf 关键配置:
max_size = 20G
compression = true
compression_level = 6
# CI 环境:跨任务共享缓存
cache_dir = /shared/ccache
3. sccache — 云端兼容缓存(Rust、C/C++)
cargo install sccache
# 或:brew install sccache
# 设置为编译器启动器
export RUSTC_WRAPPER=sccache # 用于 Rust
export CMAKE_C_COMPILER_LAUNCHER=sccache # 用于 CMake
# 使用 S3 后端
export SCCACHE_BUCKET=my-build-cache
export SCCACHE_REGION=us-east-1
sccache --start-server
sccache --show-stats
4. 预编译头(PCH)
PCH 将大型头文件预先编译一次,后续构建复用二进制结果。
# CMake ≥3.16 原生 PCH 支持
target_precompile_headers(mylib PRIVATE
<vector>
<string>
<unordered_map>
"myproject/common.h"
)
# 跨目标共享 PCH(避免重复编译)
target_precompile_headers(myapp REUSE_FROM mylib)
// 传统方式:stdafx.h / pch.h
// 所有翻译单元将 pch.h 作为第一个 include
// pch.h 包含大型系统头文件
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
PCH 对大型且稳定的头文件最有效(STL、Boost、Qt)。避免将频繁变动的项目头文件放入 PCH。
5. Unity / Jumbo 构建
将多个 .cpp 文件合并为一个翻译单元,减少头文件解析开销并改善内联效果。
# CMake ≥3.16 Unity 构建
set_target_properties(mylib PROPERTIES UNITY_BUILD ON)
# 控制批大小(默认每批 8 个文件)
set_target_properties(mylib PROPERTIES UNITY_BUILD_BATCH_SIZE 16)
# 排除特定文件(如存在 ODR 问题)
set_source_files_properties(problem.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
手动 Unity 文件:
// unity_build.cpp
#include "module_a.cpp"
#include "module_b.cpp"
#include "module_c.cpp"
注意事项:匿名命名空间(每个翻译单元独立)、头文件中的 using namespace、重复的静态变量。
6. Split-DWARF — 缩短链接时间
Split DWARF 将调试信息放入 .dwo 辅助文件,大幅减少链接器需要处理的数据量。
# GCC / Clang
gcc -g -gsplit-dwarf -o prog main.c
# CMake 全局配置
add_compile_options(-gsplit-dwarf)
# 合并 .dwo 文件用于分发(可选)
dwp -o prog.dwp prog # GNU dwp 工具
配合 --gdb-index 加快 GDB 启动速度:
gcc -g -gsplit-dwarf -Wl,--gdb-index -o prog main.c
链接时间对比(大型项目,典型情况):-g 完整 DWARF 的链接时间约为 -gsplit-dwarf 的 4×–6×。
7. distcc — 分布式编译
# 在所有机器上安装
apt-get install distcc
# 在工作机上启动守护进程
distccd --daemon --allow 192.168.1.0/24 --jobs 8
# 客户端:设置 DISTCC_HOSTS
export DISTCC_HOSTS="localhost/4 worker1/8 worker2/8"
make -j20 CC="distcc gcc"
# CMake 集成
set(CMAKE_C_COMPILER_LAUNCHER distcc)
set(CMAKE_CXX_COMPILER_LAUNCHER distcc)
与 ccache 叠加使用:CC="ccache distcc gcc" — ccache 先检查本地缓存,未命中后回退到 distcc。
8. 用 IWYU 裁剪头文件
# 安装
apt-get install iwyu
# 通过 CMake 运行
cmake -S . -B build -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=iwyu
cmake --build build 2>&1 | tee iwyu.log
# 自动应用修复
fix_include < iwyu.log --nosafe_headers
完整 IWYU 工作流见 skills/build-systems/include-what-you-use。
关于 ccache 配置选项,见 references/ccache-config.md。
相关技能
- 使用
skills/build-systems/cmake了解 CMake 项目结构 - 使用
skills/build-systems/include-what-you-use进行 IWYU 头文件裁剪 - 使用
skills/rust/rust-build-times了解 Rust 专属构建加速 - 使用
skills/debuggers/dwarf-debug-format了解 Split-DWARF 内部原理
More from killvxk/low-level-dev-skills-zh
binutils
GNU binutils 二进制操作与分析技能。适用场景:使用 ar 管理静态库、使用 strip 或 objcopy 处理二进制文件、使用 addr2line 将地址转换为源码位置、使用 strings 提取文本、或使用 c++filt 对 C++ 名称进行反混淆。触发条件:涉及 ar、strip、objcopy、addr2line、strings、c++filt、ranlib 或二进制后处理任务的查询。
1ebpf
Linux 可观测性和网络的 eBPF 技能。适用场景:使用 libbpf 或 bpftrace 编写 eBPF 程序、挂载 kprobe/tracepoint/XDP 钩子、调试验证器错误、使用 eBPF map,或实现跨内核版本的 CO-RE 可移植性。触发条件:查询 eBPF、bpftool、bpftrace、XDP 程序、libbpf、验证器错误、eBPF map 或使用 BPF 进行内核追踪相关问题。
1clang
C/C++ 项目的 Clang/LLVM 编译器技能。适用场景:使用 clang 或 clang++ 进行诊断、sanitizer 插桩、优化备注、通过 clang-tidy 进行静态分析、通过 lld 实现 LTO,或从 GCC 迁移到 Clang。触发条件:涉及 clang 标志、clang-tidy、clang-format、更好的错误信息、Apple/FreeBSD 工具链或 LLVM 特定优化的查询。涵盖标志选择、诊断调优及与 LLVM 工具的集成。
1gcc
C/C++ 项目的 GCC 编译器技能。适用场景:选择优化级别、警告标志、调试构建、LTO、sanitizer 插桩,或诊断 GCC 编译错误。涵盖调试与发布构建的标志选择、ABI 问题、预处理器宏、配置引导优化(PGO)及与构建系统的集成。触发条件:涉及 gcc 标志、编译错误、性能调优、警告抑制或跨标准编译的查询。
1cmake
C/C++ 项目的 CMake 构建系统技能。适用场景:编写或重构 CMakeLists.txt、配置源外构建、选择生成器(Ninja、Make、VS)、使用 target_link_libraries 管理目标和依赖、通过 find_package 或 FetchContent 集成外部包、启用 Sanitizer、为交叉编译配置工具链文件,或导出 CMake 包。触发条件:涉及 CMakeLists.txt、cmake 配置错误、目标属性、安装规则、CPack 或 CMake Presets 的查询。
1cpp-modules
现代 C++ 项目的 C++20 模块技能。适用场景:使用命名模块、模块分区、头文件单元、CMake MODULE_SOURCES、Clang -fmodules-ts、BMI 缓存问题,或从头文件迁移到模块。触发条件:涉及 C++20 模块、import 语句、模块接口单元、头文件单元或 BMI 文件的查询。
1