编译器缓存加速 —— 第二次编译快得多的秘密
为什么第二次编译更快
你有没有注意到:同一个 Cxxdroid 项目,第一次点编译可能要 5 秒,第二次再点可能只要 2 秒甚至更快?
这不是错觉——Cxxdroid 内置了编译缓存机制。
缓存原理
编译缓存的思路类似程序员常用的 ccache:
- 源码文件 → 哈希计算
- 头文件依赖链 → 哈希计算
- 编译器参数(比如
-std=c++17、-lboost)→ 哈希计算 - 三者拼起来算一个唯一键
- 如果这个键在缓存里存在,说明之前用完全相同的参数编译过这份代码——直接拿之前的目标文件用
- 如果缓存里没有,走正常编译流程,编译完把结果存进缓存
因为 C++ 编译的大头在预处理和模板实例化,而这两步的结果只和源码内容 + 编译器参数有关——只要这些没变,结果就完全可复用。
缓存在哪
缓存文件通常存在:
- 应用内部存储的缓存目录(Android 10+ 路径可能需要通过
adb查看) - 项目 build 目录下的子文件夹
应用通常会自动管理缓存的生命周期——缓存过大时自动清理、应用更新时自动失效(防止新旧编译器混用缓存)。
手动清理缓存
如果你修改了编译器参数、或者升级了 Cxxdroid 后编译行为异常,可以手动清理缓存:
- 系统设置 → 应用 → Cxxdroid → 存储 → 清除缓存
- 或删除项目目录下的
build/文件夹
清理后下次编译会慢一次(重新走完整编译流程),但之后又能享受缓存加速了。
缓存 vs 增量编译
注意:编译缓存和增量编译是两回事。
- 增量编译:Clang 自身的能力,只重新编译上次编译后修改过的 .c / .cpp 文件
- 编译缓存:Cxxdroid 加的外层机制,跨不同编译会话复用结果
两者叠加效果最佳:增量编译在单个会话里生效,编译缓存在跨会话时生效。
实际效果
用 Boost 做个对比:
| 操作 | 第一次 | 第二次 |
|---|---|---|
编译 #include <boost/asio.hpp> 的小程序 | 约 5-10 秒(Boost 头文件极其庞大) | 约 1-2 秒(缓存命中) |
编译 #include <vector> 的小程序 | 约 1-2 秒 | 约 200-500ms |
Boost 这种大型库的缓存命中率接近 100%——因为你基本不会去改 Boost 的头文件本身。