如何使用ccache和sccache提升云端c++编译速度? (分布式缓存)

2次阅读

ccache在云端CI中基本失效,因其仅支持本地缓存、对路径和编译选项敏感、无法跨机器共享且不兼容-fdebug-prefix-map等现代选项;sccache需配置远程存储并禁用非确定性选项才能真正生效。

如何使用ccache和sccache提升云端c++编译速度? (分布式缓存)

ccachesccache 做云端 c++ 编译加速,关键不在于“装上就快”,而在于缓存是否真正被命中、是否跨机器共享、以及是否绕过了编译器本身的不可缓存行为。单机 ccache 在 CI/CD 中几乎无效;真正起效的是带远程存储的 sccache,且必须正确配置编译环境使其生成可复用的哈希键。

为什么 ccache 在云端 CI 中基本失效

ccache 默认只做本地文件系统缓存,且对绝对路径、临时目录、宏定义顺序极度敏感。CI 环境中每次构建都在全新容器或虚拟机里运行,CCACHE_BASEDIR 若未统一,所有缓存键都会错乱;更致命的是,它无法处理 -fdebug-prefix-map-frecord-gcc-switches 等现代构建系统默认启用的选项,导致 99% 的编译单元无法命中缓存。

  • CI 构建路径通常是随机的(如 /tmp/xyz123/build),ccache 把路径嵌入哈希,缓存完全不复用
  • Clang/GCC 新版本默认加 -frecord-gcc-switches,记录完整命令行(含绝对路径),进一步破坏一致性
  • 没有内置 S3/GCS/redis 后端,无法实现多 runner 共享缓存

sccache 必须启用远程存储并禁用非确定性选项

sccache 原生支持 S3、GCS、redishttp 后端,但默认仍走本地磁盘。要让它在云端生效,必须显式配置远程存储,并同步调整编译命令以消除哈希扰动。

  • 启动时必须指定后端:例如 sccache --start-server --cache-dir /dev/shm --s3-bucket my-ccache-bucket --s3-region us-east-1
  • 编译前导出环境变量export SCCACHE_BUCKET=my-ccache-bucketSCCACHE_REGION=us-east-1,且确保 AWS 凭据可用(推荐使用 IRSA 或 workload identity)
  • 在 CMake 中强制关闭非确定性选项:add_compile_options(-fdebug-prefix-map=/tmp/build= -frecord-gcc-switches),其中 /tmp/build 需与 CI 实际工作目录一致
  • 避免使用 -g 以外的调试格式(如 -gdwarf-5),某些版本 sccache 对新版 DWARF 支持不稳定

如何验证缓存是否真实生效

别只看 sccache --show-stats 里的 hit rate——它可能显示 80%,但全是本地旧缓存。真正要看的是远程后端的实际 GET/PUT 请求量,以及编译日志中每条命令前是否出现 [sccache] Cache hit

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

  • 在 CI 脚本中加入:sccache --show-stats | grep -E "(Cache hits|Cache misses)",并在每次构建后清空本地缓存(sccache --stop-server && rm -rf /tmp/sccache)来排除本地干扰
  • 检查 S3 bucket 是否有新 Object 写入:对象名形如 ff/ff1234abcd.../output.o,若连续多次构建无新增,则说明没上传——大概率是编译命令哈希不一致
  • 开启 debug 日志:SCCACHE_LOG=debug sccache --dist-status,观察是否报 Failed to get cache entry: key not found,这通常意味着预处理器输出不一致(比如头文件时间戳、__DATE__ 宏)

分布式编译(distcc)和 sccache 不要混用

sccache 自带分布式编译能力(通过 --dist-server),但它和传统 distcc 是互斥的。若你在 CMake 中设置了 CMAKE_CXX_COMPILER_LAUNCHER=distccsccache 就不会介入编译流程,等于白配。

  • 只用 sccache 就够了:它既做缓存又做分发,无需额外部署 distcc 集群
  • 确保 CXX 指向 sccache:例如 export CXX="sccache clang++",而不是 export CXX="clang++" + 单独 launcher
  • 如果已有 distcc 流程,必须彻底移除所有 distcc 相关环境变量DISTCC_HOSTSCCACHE_PREFIX=distcc

最常被忽略的一点:C++ 模板实例化和宏展开高度依赖头文件内容与顺序,哪怕一个头文件里多了一个空格,哈希就全变。所以不要指望第一次构建就能高命中——先跑通一次完整构建,让缓存“热起来”,再观察后续增量构建的收益。否则你看到的永远是 0% hit。

text=ZqhQzanResources