CCache的便捷接入

2,687 阅读3分钟

#编译时间优化

参考资料:

CCache 我差一点就和你擦肩而过

[贝聊科技]如何将 iOS 项目的编译速度提高5倍

优化 iOS 项目的构建时间

提示: 本文大部分内容与上述文章重复,只是增加了替换@import脚本儿

随着我们项目越来越大,全量编译动辄十分钟起步,相当影响开发时候的思路和时间,所以我们准备引入CCache

  • Xcode 编译缓存
    • archive 模式会忽略缓存
    • DerivedData 目录经常出问题
  • CCache
    • archive 不会忽略缓存
    • 命中率基本稳定

使用 CCache 大体上可以提升70%的编译时间。

安装CCache

使用方法: 手动调用 chmod -R 777 setup.command && ./setup.command给脚本权限并执行

脚本名称:setup.command 脚本内容:

if command -v ccache >/dev/null 2>&1; then
    echo "CCache 已经安装"
else
    if command -v brew >/dev/null 2>&1; then
        echo "HomeBrew已经安装,开始安装ccache"
        brew install ccache
    else
        echo "HomeBrew没有安装,安装之后开始安装ccache"
        ruby_path=`which ruby`
        echo $ruby_path
        $ruby_path -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
        brew install ccache
    fi
fi

Xcode设置

电脑我们已经安装好了 CCache,接下来我们要做的就是项目设置

  • 项目关闭 Enable Module

  • 新建 Macro CC 这个配置就是让 Xcode 自动运行CCache脚本

  • 替换@import脚本

关闭了 Enable Module之后 我们要删除工程里面用到的所有 @import的代码并换成 #import <> 这一步的难点在于Pod库中的@import,改动代码之后,下次Pod更新再次回滚 怎么能每次编译之前,把第三方里面的 @import替换掉。我第一想到是用脚本

使用方法: chmod -R 777 changeImportMethod.py && chmod -R 777 Pods && python changeImportMethod.py

脚本名称:changeImportMethod.py

脚本内容:

# coding=utf-8

import os
# python2 就可以执行 不需要依赖别的库
# 该脚本需要执行chmod 777 赋予读写权限 同时也要在Pod文件夹那里执行一次 确保允许读写
project_path = os.getcwd() + "/Pods" #项目根目录
print(project_path)

suf_set = ('.h', '.m')

# 准备被覆盖的
preparationSet = {
    "@import Foundation;":"#import <Foundation/Foundation.h>",
    "@import UIKit;":"#import <UIKit/UIKit.h>",
    "@import Security;":"#import <Security/Security.h>",
    "@import PassKit;":"#import <PassKit/PassKit.h>",
    "@import Contacts;":"#import <Contacts/Contacts.h>",
    "@import QuartzCore;":"#import <QuartzCore/QuartzCore.h>",
    "@import CoreLocation;":"#import <CoreLocation/CoreLocation.h>",
    "@import CoreGraphics;":"#import <CoreGraphics/CoreGraphics.h>"
    }

# 遍历文件,符合规则的进行重命名 
for (root, dirs, files) in os.walk(project_path):
    for file_name in files:
        if file_name.endswith(suf_set):
            # print('-----fileName-------' + file_name)
            with open(os.path.join(root, file_name), 'r+') as f:
                s0 = f.read()
                f.close()
                for key in preparationSet:
                    if key in s0:
                        print('========needChange========' + root +"/"+ file_name)
                        with open(os.path.join(root, file_name), 'r+') as f4:
                            s1 = f4.read().replace(key, preparationSet[key])
                            print(key + ' ------> ' + preparationSet[key])
                            f4.seek(0)
                            f4.write(s1)
                            f4.truncate()
                            f4.close()

脚本写完,接入就很简单了,我们需要在编译工程源代码之前运行我们的脚本修复。 于是新增一个Run Scripts

  • CocoaPods配置 在podfile中修改
post_install do |installer_representation|
  installer_representation.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      if target.name != '你要忽略的库名' && target.name != '你要忽略的库名'
        config.build_settings['CLANG_ENABLE_MODULES'] = 'NO'
        config.build_settings['CC'] = '$(SRCROOT)/../ccache-clang'
        config.build_settings['CXX'] = '$(SRCROOT)/../ccache-clang++'
      end
    end
  end
  system 'chmod -R 777 setup.command &&  ./setup.command'
end

准备做什么

  • 提升缓存命中率

通过命令 ccache -s 可以查看 CCache 的整体缓存命中率。要使 CCache 真正能减少编译时间,命中率大约要达到 90% 。前文已经提过,频繁地缓存 miss 会比不使用 CCache 还慢,因此在集成 CCache 后需要保证90%的缓存命中率,才能确实地提高构建速度,如果发现缓存命中率过低,则需要分析日志排查原因。我们项目目前试过的几次缓存命中能到50%,还有很大优化余地.

  • 移除 Precompiled Prefix Header

使用了 PCH 文件是最常见的导致缓存命中率过低的原因。很多项目都会为了方便,把一些常用的类在 PCH 中 import 一次,而在编译时 PCH 的内容会附加在每个文件之前,PCH 内容的改变会导致整个编译对象的全部文件的内容改变,也就导致全部 CCache 缓存失效。如果你遇到过明明只修改了一两个源文件,运行项目却会全量编译的情况,看看是不是PCH里面import了太多依赖,如果暂时无法移除 PCH 则尽量减少里面 import 的文件。

  • 清理废弃代码

没有代码的编译速度能快得过「没有代码」,这是很浅显的道理,不过实现起来可能工作量较大。在公司业务快速迭代和更新时很容易就会产生一些不再使用的模块,定期清理既能减少项目的构建时间也能减小安装包的体积,一举两得。如果觉得这些代码以后还会用得上,可以只移除 Xcode 项目的引用而保留下来文件以作参考。