layout: post
title: 'Xcode项目编译优化'
subtitle: '随着项目工程的迭代,代码量不断的增加,扩展功能不断的被引入,项目的整体编译时间开始变长。'
categories: 技术
tags: xcode 编译优化
前言
随着项目工程的迭代,代码量不断的增加,扩展功能不断的被引入,项目的整体编译时间开始变长。
研发在开发/调试过程中容易被过长的编译时间打断思路,所以需要定期对项目的编译时间做个体检。
采样编译阶段耗时的多种方法
显示Xcode编译耗时
在命令行中输入,可以开启编译耗时显示。在Xcode在每次编译完成后,在运行窗口中显示编译时间。
$ defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES
使用Xcode自带的编译耗时分析
在Xcode的菜单中选择 Product > Perform Action > Build With Timing Summary
来获得编译耗时信息
Showing Recent Messages
Build Timing Summary
CompileC (2770 tasks) | 649.139 seconds
SwiftCompile (209 tasks) | 75.789 seconds
Ld (57 tasks) | 9.891 seconds
SwiftEmitModule (27 tasks) | 9.002 seconds
SwiftDriver (27 tasks) | 4.057 seconds
Copy (2022 tasks) | 1.863 seconds
CompileMetalFile (8 tasks) | 1.290 seconds
WriteAuxiliaryFile (708 tasks) | 1.287 seconds
CpHeader (941 tasks) | 1.276 seconds
PhaseScriptExecution (8 tasks) | 0.536 seconds
MetalLink (1 task) | 0.332 seconds
RegisterExecutionPolicyException (61 tasks) | 0.243 seconds
SwiftDriver Compilation Requirements (27 tasks) | 0.237 seconds
Touch (61 tasks) | 0.209 seconds
ProcessInfoPlistFile (62 tasks) | 0.110 seconds
SwiftDriver Compilation (27 tasks) | 0.085 seconds
CodeSign (1 task) | 0.066 seconds
CpResource (6 tasks) | 0.056 seconds
ExtractAppIntentsMetadata (23 tasks) | 0.049 seconds
SwiftMergeGeneratedHeaders (27 tasks) | 0.038 seconds
Libtool (3 tasks) | 0.037 seconds
ProcessProductPackagingDER (1 task) | 0.003 seconds
CopyPlistFile (1 task) | 0.002 seconds
ProcessProductPackaging (2 tasks) | 0.001 seconds
查看Xcode的Build Reprot
在Xcode菜单中选择View > Navigators > Report
,查看编译报告
Swift代码编译耗时警告
在 Xcode 项目的 Other Swift Flags中添加这两个提示,当函数/表达式编译时长超过 100毫秒 显示警告
-Xfrontend -warn-long-function-bodies=100
-Xfrontend -warn-long-expression-type-checking=100
在 Swift 编译器性能[2]中,Apple 官方提到了几个诊断选项:
- -driver-time-compilation
- -Xfrontend -debug-time-function-bodies,开启Swift文件中函数体编译耗时警告
- -Xfrontend -debug-time-expression-type-checking,开启Swift文件中表达式编译耗时警告
- -Xfrontend -print-stats
- -Xfrontend -print-clang-stats
- -Xfrontend -print-stats -Xfrontend -print-inst-counts
使用XCLogParser进行日志分析
XCLogParser可以将xcactivitylog
转换为JSON
文档,也可以生成分析报告(json
, flatJson
, summaryJson
, chromeTracer
, issues
或 html
)
可用于
- 了解并详细跟踪构建时间。
- 自动检索单元测试结果、警告和错误。
- 构建其他开发人员工具,以便在Xcode之外使用。
- 自动和持续地交付数据以进行历史分析。
# 在当前目录生成报告,使用 --project 可以自动定位xcactivitylog位置
$ xclogparser parse --project AAA --reporter html
分析日志
首次编译,157秒(会生成缓存,多发生在切换分支后)
无变动编译,11.8秒
- SwiftLint(3.2秒)
- [CP] Embed Pods Frameworks(5.0秒)
修改文件后编译,38.84秒(开发/调试场景)
- Planning target AAA(4.3秒)
- Emitting module for AAA (6.9秒)
- Complie AAA (12秒)
- Link AAA(1.2秒)
- SwiftLint(3.4秒)
- [CP] Embed Pods Frameworks(5.0秒)
- Sign(2.4秒),受文件数量影响
优化方案
Swift代码优化
解决编译时间过长的代码,多数为类型推断耗时过长,可以手动指定变量类型。
SwiftLint脚本优化
当前项目中,Lint+Correct耗时在3.4秒,单独开启Lint只需要耗时0.7秒
Lint 从3.4
秒 减少到 0.7
秒
优化Debug环境下编译参数
- Xcode默认使用
SHA-256
签名,本地调试阶段可以改成更快的SHA-1
,不会有安全性问题,在Other Code Signing Flags
添加--digest-algorithm=sha1
- iOS校验签名只对二进制签名,其他文件不签名也不会报错,可以过滤文件减少签名文件数量,在
Other Code Signing Flags
添加--resource-rules=/path/to/rule.plist
,rule.plist
文件如下
--resource-rules=CodeSigningFileRule.plist
--resource-rules=$(SDKROOT)/CodeSigningFileRule.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>rules</key>
<dict>
<key>.*</key>
<false/>
</dict>
</dict>
</plist>
Sign时间从2.7
秒减少到0.2
秒
优化结果
测试环境:M1 Max + 32G,同时只编译一个项目
优化前 | 优化后 | |
---|---|---|
首次编译(分支切换后) | 157 秒 | 152.27秒 |
代码修改后编译(主要开发场景) | 38.8 秒 | 31.3 秒 |
无修改编译 | 11.8 秒 | 6.7 秒 |
进一步优化
从日志上可以看出,代码发生修改后,AAA项目整体发生了重新编译,而Pod库的编译产物被复用。
可以得出结论模块Pod化也可以提升编译速度。
本次未针对首次编译进行优化,主要是目前交叉开发的情况较少。后续可以从固定资源文件,将动态库转为静态库的方向来优化首次编译的速度。