前言
之前一篇介绍 CCache 的文章 https://zhuanlan.zhihu.com/p/27584726 探讨了如何使用 CCache 来优化应用构建的时间, 评论里面收到了不少朋友反馈在使用的过程遇到了困难, 最后无法成功应用上 CCache. 其中的绝大部分问题我们在贝聊项目的集成过程中也遇到过, 本文主要针对这些问题给出相应的解决方案, 并从其他方面给出一些优化应用构建时间的建议.
提升缓存命中率
通过命令 ccache -s 可以查看 CCache 的整体缓存命中率. 要使 CCache 真正能减少编译时间, 命中率大约要达到 90% . 前文已经提过, 频繁地缓存 miss 会比不使用 CCache 还慢, 因此在集成 CCache 后需要保证 90% 的缓存命中率, 才能确实地提高构建速度, 如果发现缓存命中率过低, 则需要分析日志排查原因.
移除 Precompiled Prefix Header
使用了 PCH 文件是最常见的导致缓存命中率过低的原因. 很多项目都会为了方便, 把一些常用的类在 PCH 中 import 一次, 而在编译时 PCH 的内容会附加在每个文件之前, PCH 内容的改变会导致整个编译对象的全部文件的内容改变, 也就导致全部 CCache 缓存失效. 如果你遇到过明明只修改了一两个源文件, 运行项目却会全量编译的情况, 看看是不是 PCH 里面 import 了太多依赖, 如果暂时无法移除 PCH 则尽量减少里面 import 的文件.
以文件内容作为编译缓存的 Key
因为常见的 git 切换分支, pod update 等操作都会造成大量文件的最后编辑时间变化, 如果用文件最后编辑时间作为缓存的 key, 经常会看见切换 git 分支或者 pod update 之后大量文件缓存失效. CCache 默认就是用文件内容的 MD4 摘要值来作为缓存 key 的一部分的, 只要不加上 file_stat_matches 选项即可. 虽然计算并对比文件内容的摘要值比简单对比文件的修改时间和大小要耗费更长的时间, 但经过实践发现使用文件内容来作为 key 会有更稳定的编译优化效果, 以下是我目前在用的效果比较好的 CCache 配置:
- #!/bin/sh
- if type -p ccache>/dev/null 2>&1; then
- export CCACHE_MAXSIZE=10G
- export CCACHE_CPP2=true
- export CCACHE_HARDLINK=true
- export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,pch_defines
- exec ccache /usr/bin/clang "$@"
- else
- exec clang "$@"
- fi
只在 Release 构建启用 CCache
在使用 Debug 配置开发期间, Xcode 本身自带增量编译, 只是在使用 Release 配置构建 AdHoc 或者 AppStore 的时候不能使用增量编译. 因此在 Debug 模式下启用 CCache 其实意义不大, 开发时文件频繁变更导致缓存命中率低, 反而会拖慢日常开发节奏.
对单个 Pod 不启用 CCache
使用 CCache 需要关闭 Clang Module 功能, 而有些第三方库因为使用了 @import 语法导致如果关闭 Clang Module 则无法使用 @import 语法继而导致编译出错. 这种情况可以单独设置一个 Pod 不要启用 CCache 即可.
下面的 Podfile 配置代码同时演示了如何只在 Release 构建启用 CCache 以及对单个 Pod 不使用 CCache:
- # Podfile
- target 'YourApp' do # 替换为你的 target 名
post_install do |installer_representation|
installer_representation.pods_project.targets.each do |target|
- if config.name != 'Debug' && target.name != 'SomePod' # 替换为你想要排除的 Pod 的名字
- config.build_settings['CC'] = '$(PODS_ROOT)/ccache-clang' # 替换为你的 ccache-clang 文件路径
- end
- end
- end
- end
其他的优化点
这些优化点与 CCache 无关, 但我尝试过之后发现对编译速度和开发体验有一定提升, 因此一并列出.
调整编译的最大并发数
更新: Xcode 9.3 发布后, 我又用同样的项目验证了一次, 得出了近似的结果, 但差异较小, 建议先进行 Benchmark 再决定是否要应用到自己项目中.
我之前通过这条命令
defaults write com.apple.dt.Xcode IDEBuildOperationMaxNumberOfConcurrentCompileTasks `sysctl -n hw.ncpu`
把编译时的最大并发数设置为 CPU 的核心数, 没想到这竟然不是最好的配置. 我最早是从下面这篇文章发现的: The best hardware to build with Swift is not what you might think | 领英 https://www.linkedin.com/pulse/best-hardware-build-swift-what-you-might-think-jacek-suliga
来源: https://juejin.im/post/5ad4afb16fb9a028d56796e7