[iOS]CCache 让你的编译时间飞起来

原文地址:Using ccache for Fun and Profit 做者 Peter Steinbergerios

咱们的 PSPDFKit 项目超过 60 万行代码,而且代码量还在增加。尽管咱们致力于写简洁而高效的代码,可是这个项目很大,并且有许多边界状况须要尤为注意。在 PSPDFKit 5 for iOS 项目上,编译时间尤为成为一个使人头痛的问题:每次编译都很慢。git

咱们的安卓 SDK 也有一样的问题,几个月前咱们的安卓负责人在技术栈中引入了 ccache 来处理冗长的 C++ NDK 编译时间,我也是从那个时候开始接触 ccache。github

ccache 是个啥?

ccache 是一个编译缓存器,它会在实际编译以前先检查缓存。它有直接和预处理模式,并且因为在 Clang 3.2 版本以前是不支持 ccache 插件,因此在 Clang 3.2 以前会有一些问题,可是如今 Clang 的版本是 3.2.3,因此没有 Clang 不支持的问题。ccache 是一个具备悠久历史的项目,其主要焦点是快速正确。shell

网上搜到“ccache xcode”的信息都是过期无效的信息,通过我快速的尝试网上的方法,都没法配置好使其正常工做。随着咱们的代码库愈来愈复杂,同时咱们的 Jenkins 工做集群数也有 10 台 Mac,如今测试时间从几乎没法忍受变成了正真没法忍受。在 Twitter 抱怨如今天天的工做就是管理 Jenkins 工做集群以后,Facebook 的 Christian Legnitto(他以前在 Apple 负责 OS X 版本管理工做)建议咱们尝试 ccache编程

Let’s get started

使用如下命令安装 ccachexcode

brew install ccache
复制代码

若是你没安装 Homebrew,请移步这里,先去安装 Homebrew,若是你不想移步,就直接使用如下命令安装 Homebrew缓存

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
复制代码

为了让 Xcode 调用 ccache,咱们须要一个小脚原本配置一些环境变量,而后再调用 ccache。将这个脚本保存到您项目的某个地方,并将其命名为 ccache-clangruby

#!/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,file_stat_matches  
exec ccache /usr/bin/clang "$@"
else
exec clang "$@" 
fi
复制代码

根据你的具体状况,若是你的项目中有 C++的文件,你可能还须要一个命名为 ccache-clang++ 的脚本,并在这个脚本里这么写:curl

#!/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,file_stat_matches  
exec ccache /usr/bin/clang "$@"
else
exec clang++ "$@" 
fi
复制代码

这样看起来是否是有点复杂,若是没有命中缓存,那么将会按照以前的编译方式同样编译,而不是报 ccache not found(找不到缓存)的错误(ccache 内置 shell 脚本,因此检查缓存很迅速)。工具

建立 shell 脚本方法:

建立           touch ccache-clang
打开脚本        open -a xcode ccache-clang
粘贴脚本内容
执行脚本        chmod 755 ccache-clang
复制代码

若是去学习 ccache 的配置,你会发现有不少选项可选。上面咱们使用的是一种至关激进的缓存策略,同时运行良好。对于你本身的项目,你可能在没有 CCACHE_SLOPPINESS 的状况下开始,而后在一切运行良好的状况下一次性添加缓存。

这里最重要的参数是 CCACHE_CPP2,这个参数用于解决 Clang 将处理预处理器的文件输出,并可能会发现许多你没有注意到的潜在问题,例如因为宏扩展致使的没必要要的括号。使用此选项会稍微减慢编译时间,可是要比彻底没有使用 ccache 要快得多。Peter Eisentraut 写了一篇关于这个问题的好文章

您还须要在 Xcode 中定义 CC 变量。在 PSPDFKit 中,咱们在 .xcconfig 文件中执行此操做,这个文件在咱们全部项目中共享(这是一个很好的统一的项目配置,和易于阅读和查找)。同时,您能够直接在 Xcode 项目设置内配置:

CC = "$(SRCROOT)/../Resources/ccache-clang"
复制代码

就这么多了!下次编译的时候会比正常慢一点,你能够在终端中使用 ccache -s 来查看 ccache 是否正常工做。刚开始时应该有不少缓存没有命中,可是当缓存开始渐渐替代以后的编译时,编译速度将会变得快起来。

坑来了

路不平的地方就有坑:ccache 有一些缺点。

不支持 Clangmodules,若是检测到 -fmodulesccache 就会失效。所以,为了兼容 ccache,你须要用老旧的 # import <UIKit/UIKit.h> 替换你项目中全部优雅的 @import UIKit,以及全部使用 ccache 带来的问题,比方说宏的问题。在 PSPDFKit 项目中咱们采用了 Objective-C++ 的形式,当咱们使用不少 C++ 代码时,就没法使用 modules 了,因此这一点(ccache 不支持 modules)并无影响到咱们。 modules 会自动连接用到的 framework,可是在禁用了 modules 之后,你须要手动添加用到的 framework,这个工做很无趣,可是也很快就作完。

还须要中止使用 .pch。苹果不推荐使用 .pch,并且通常认为使用 .pch 是很差的编程风格,哪里用到就在哪里导入会比 .pch 要好。对咱们而言,删除那些 .pch 仍是很容易的。固然,ccache 无法帮你缓存 Swift 文件。虽然 Swift 也使用 Clang,可是ccacheSwift 文件一筹莫展。也许 ccache 最终会支持 Swift,但我期望不上。由于 Swift 至今没有稳定,甚至咱们要在 Swift 的两个版本之间作二进制兼容,咱们无法用 Swift 来编写咱们的 SDK,因此 ccache 不支持 Swift 的问题,对咱们不是问题。

在编译期间,咱们应该随时监视项目是否抛出不兼容的警告。请参阅“不支持的编译器”选项。我花了至关一部分时间去处理这些不兼容的问题。设置 CCACHE_LOGFILE 临时环境变量将有助于咱们精肯定位错误:ccache 将会提示那些标识是有问题的,以及缓存命中和未命中的具体状况。

steipete@steipete-rmbp ~ $ ccache -s
cache directory                     /Users/steipete/.ccache
primary config                      /Users/steipete/.ccache/ccache.conf
secondary config      (readonly)    /usr/local/Cellar/ccache/3.2.3/etc/ccache.conf
cache hit (direct)                 42530
cache hit (preprocessed)           18147
cache miss                         28379
called for link                     1344
called for preprocessing             645
compile failed                         1
preprocessor error                     2
can't use precompiled header        2567
unsupported source language           12
unsupported compiler option        11564
no input file                          2
files in cache                    124223
cache size                           8.7 GB
max cache size                      15.0 GB
复制代码

搞这个值不值?

给你说一下咱们使用的状况,使用了 ccache 之后,咱们的编译运行时间平均为 8 分钟,以前咱们没有用 ccache 的时候是 14 分钟。使用 ccache 以前在最快的 MacBook Pro 上编译打包整个 PSPDFKit 须要 50 分钟,使用了以后,时间为 15 分钟。添加 ccache 到咱们的技术栈是一个巨大的进步,真后悔我没有早点知道这个那么棒的工具!

Precompiled Header 问题

Anton Bukov 说经过禁用 GCC_PRECOMPILE_PREFIX_HEADER,开启 GCC_PREFIX_HEADER 的方式来处理这个问题。

NewPan 的文章集合

下面这个连接是我全部文章的一个集合目录。这些文章凡是涉及实现的,每篇文章中都有 Github 地址,Github 上都有源码。

NewPan 的文章集合索引

若是你有问题,除了在文章最后留言,还能够在微博 @盼盼_HKbuy 上给我留言,以及访问个人 Github

相关文章
相关标签/搜索