蓝盟IT小贴士,来喽!
概要
经过多年的发展,柚子iOS项目代码达到了40W行的规模,使用的Pod库数量达到了110个,App Store安装包210M,在如此大的项目规模上(CI机MAC配置, 时间: 20min版)、(开发设备iMac :Retina 5K、27英寸、2017融合硬盘; 时间: build30min )打包、编译问题已成为我们团队不可避免的痛苦,极大地影响了我们的研发效率和与其他团队的合作。
我们需要在13年的ci机上同时承担7、8个项目、多个分支的打包任务,在多个项目同时打包的情况下,就显得特别吃力。
在硬件资源有限的情况下,且不影响现有业务的情况下,如何解决摆在这些团队面前的难题已成为我们迫切的需要,近半年来,我们一直在寻找加快打包速度的方法。
二、编译的高速探索与尝试
一、CCache
CCache是一个编译缓冲区,是一种可以缓存编译中间产物的工具
其原理是,用ccache编译器编译项目的源文件,缓存编译生成的信息,从而在下一次编译时利用该缓存加速编译,当前支持的语言是c、c、ook
Ccache我们经过工程的尝试,确实在某种意义上大大提高了我们提包的速度。 柚子iOS Ci套餐从目前为止最快的20min到最快的10min,确实给我们带来了很好的提升,大大加快了我们项目的打包速度。 我们的项目运转了几个月后,关于我们项目的状况也发现了一些问题。 现在总结以下几点。
好处:
满足我们要求的无入侵、不影响现有业务的要求,无入侵、开发者不感知。
确实,可以大幅提高编译速度,在葡萄柚项目中最快时可以提高3倍以上的编译速度。
不需要对项目进行大的调整,只需要部署相关的环境和脚本支持。
没有必要改变开发工具链
在同一目录中,CCache的缓存命中率相对稳定。
我们的项目有几个问题
如果没有缓存,第一个包编译的时间将接近原来的两倍,原来的20 min,最初的40 min,如果资源紧张,则为70min。修改引用较多的文件(如修改公用库和基础库)会导致大范围的缓存容易被禁用,比不使用ccache时慢。
多个项目相同的组件不支持缓存共享。 有多个分支包的需求。 如果重命名目录,缓存将无效。
我们公司的Ccache最大缓存上限约为18GB,Debug/Release区别缓存、柚子iOS项目占用5GB缓存,多个项目、多个分支容易超过上限,一台Ci机多个项目
对机械硬盘的读写要求很高,如果不是所有的固态硬盘,速度的影响很大。
缓存不支持克隆模块。 由于Xcode不会自动部署系统框架(如AVFoundation和CoreLocation ),因此编译失败。
CCache不支持PCH文件
CCache目前不支持Swift
2 .搜索静态库二进制文件
我们应用Ci的Ccache已经提高了近两倍的外包速度,但存在的问题也暴露出来了。
在去年的一个技术周会上,我们的大佬提出了使用二进制编译的自研任务,进一步提高了研究开发效率。 受大佬启发后,一直走在实践和探索二进制的道路上。
我们的项目使用CocoaPods来管理第三方库和私有库的依赖关系,应该是大多数项目的标配。 现在也是纯Objective-C的项目,有少量的c,没有引入Swift。
3 .调查的二进制组件方案
以下是研究的几个主要方案和最后没有采用的理由。 这些方案各有限制,但给了我与最终方案具有同样价值的启发。
3.1、卡特
Carthage可以将一些变化不大的库打包到框架中,然后将其部署到主工程中,从而缩短开发过程中的编译时间。 Carthage可以很容易地调试源代码。 由于我们现在大规模使用CocoaPods,转用Carthage进行软件包管理需要很多转换工作,变化太大,没有我们的入侵,不会影响现有的业务,所以没有考虑这个方案。
3.2、可口袋-包装器
cocoapods-packager可以将任何pod打包到静态库中,从而减少重复编译的时间,在某种程度上也有其自身的问题。优化不完全,只优化第三方和私有Pod的编译速度,对经常更改的其他业务代码束手无策。
私有库和第三方库的后续更新很麻烦,在源代码发生修改后,需要重新打包内部上传的Git仓库。
二进制文件过多会减慢Git的操作速度(目前还没有部署Git的LFS )。
难以调试源代码,不共享编译缓存
打包到静态库的过程很慢,需要通过pod lint,各组件之间有层次地依赖,在现有阶段很难实现。
3.3、可口可乐二进制
Cocoapods-Binary(Cocoapods官方推荐的二进制插件)不是像CocoaPods-Packager那样只针对单个私有库,而是瞬间生成二进制软件包并进行缓存原理是通过CocoaPods提供的pre_install hook在pod安装的prepare阶段被当前的pod安装上下文拦截,fork发出独立的installer将源代码clone转换为pod/\
如果单个源无法实现服务器端缓存,并且不支持二进制包的版本,则在pod install之后会添加二进制包的生成,从而在一定程度上影响pod install的速度。
当开发者剪切源调试时,二进制缓存将一起清空,需要重新编译。
多个项目、不同分支的相同组件依然不能共享
只支持框架,我们的项目现状需要比较大的头文件引用方式的改变。
文/上海蓝盟 IT外包专家