Xcode 26 Compilation Caching 值得开吗?2026 CI 判断

Xcode 26 Compilation Caching 值得开吗?2026 CI 判断

症状:Clean Build 或频繁切换分支后,远程 Mac CI 仍然反复编译相同源文件,但流水线总时长没有稳定下降。

最快解法:先用诊断信息确认 Compilation Caching 是否命中,再用同一提交、同一 Scheme 和同一节点做开启/关闭对照;只有能够长期保留缓存的 Runner,才适合灰度放量。

适用负载与初步结论

Xcode 26 的 Compilation Caching 是可选择启用的编译能力。Apple 官方资料确认,它可以缓存特定源文件输入产生的编译结果,在相同输入再次参与编译时尝试复用;频繁切换分支和执行 Clean Build 的工作流,更值得进入验证范围。Xcode 26 Release Notes

但“启用缓存”不等于“所有项目都会变快”。真正影响结果的是输入是否重复、构建参数是否稳定、Runner 是否保留工作目录,以及编译是否确实占据流水线的大部分时间。

你可以先按三种结论分流:

  • 进入灰度测试:频繁切换分支,Clean Build 较多,同一节点能够保留工作目录和缓存目录,Scheme、SDK 与构建参数也相对稳定。
  • ⚠️ 暂缓全量启用:Runner 每次任务后销毁,缓存无法跨任务保留,或者签名、测试、依赖下载和脚本已经占据主要时间。
  • 暂不启用:磁盘空间紧张、共享节点隔离不足,或者每个任务都会动态修改大量输入和构建参数。

这篇文章适合三类人:频繁切换分支或执行 Clean Build 的 Apple 平台开发者;维护自托管远程 Mac Runner 的 DevOps 工程师;以及需要控制共享节点稳定性、发布复现和容量规划的研发平台负责人。

截至 2026 年 9 月 3 日,Apple 系统要求页面列出 Xcode 26.6 为稳定版本,并列出 Xcode 27 beta 4 作为测试版本;Xcode 26.6 要求 macOS Tahoe 26.2 或更高版本。Xcode 系统要求 本文只讨论 Xcode 26 的已确认行为,不把测试版行为套用到稳定版。

命中证据与缓存边界

四种机制分别取证

在 CI 里,下面四种机制经常被统称为“缓存”,但它们解决的问题不同:

  1. Compilation Caching:复用编译器针对特定源文件输入产生的编译结果。
  2. DerivedData:保存中间构建产物、索引和其他 Xcode 工作数据。
  3. 依赖下载缓存:复用包管理器或依赖系统已经下载的源码、二进制包。
  4. 增量构建:根据源文件和依赖关系,只重新处理发生变化的目标。

Apple 的 Build Settings Reference 列出了 COMPILATION_CACHE_ENABLE_CACHING,并提供 COMPILATION_CACHE_ENABLE_DIAGNOSTIC_REMARKS,用于输出与缓存编译任务有关的诊断信息。Build Settings Reference

因此,DerivedData 没有被删除,不代表 Compilation Caching 已经命中;依赖下载变快,也不能算编译缓存产生了收益。你需要把诊断日志、编译任务和流水线阶段分别核对。

三类重复构建样本

建议固定一个项目提交,连续记录三类任务:

  • 首次构建:建立完整基线,确认编译、链接、签名、测试和脚本分别占用多少时间。
  • 相同输入复跑:不改变提交、Scheme、SDK、构建参数和节点,观察是否出现缓存诊断,以及同类源文件是否减少实际编译。
  • 切回历史分支:先构建分支 A,再切到分支 B,最后切回 A,观察原本相同的输入能否复用。

不要只看流水线顶部的总耗时。你需要在日志中确认 Compilation Caching 的诊断信息,再结合 xcodebuild 的构建计时摘要判断编译阶段发生了什么。Apple 官方文档支持使用 -showBuildTimingSummary 输出构建时间信息。Xcode 增量构建计时文档

一个有效命中至少应满足以下条件:

  • 相同输入的重复编译任务出现缓存相关诊断;
  • 编译阶段的任务数量或实际耗时出现可重复变化;
  • 变化在多次任务中方向一致,而不是只发生一次;
  • 无缓存构建仍然能够独立完成;
  • 缓存开启不会改变最终归档、测试或签名结果。

如果只能看到 DerivedData 目录继续增长,或者流水线总时长偶尔变短,但没有编译阶段证据,就不能判定为命中。

编译收益与全链路收益

两条时间轴分开统计

Compilation Caching 直接影响的是编译相关任务,而不是整条 CI 流水线。即使编译阶段变快,以下环节仍可能让总时长变化不明显:

  • Swift 或 Objective-C 编译;
  • 模块准备与依赖扫描;
  • 链接和二进制处理;
  • 代码签名与导出;
  • 单元测试、UI 测试和模拟器启动;
  • 依赖解析、下载与脚本任务;
  • 上传制品或发布归档。

你应把收益拆成两个指标:

编译收益:只比较编译阶段的耗时、任务数量和缓存诊断。

流水线收益:比较从任务开始到成功结束的完整耗时,同时记录签名、测试、脚本和依赖下载的占比。

不要使用没有来源的固定提升比例做决策。Apple 确认了适用工作负载和相关设置,但没有承诺所有项目都会获得统一的性能收益。任何耗时、提升百分比和节点性能结论,都必须来自你的实测或可靠测试资料。

方案对照表

判断维度 更适合开启 更适合暂缓或关闭
源文件输入 多次构建反复处理相同源文件 每次任务都生成或修改大量输入
分支行为 经常切换分支并回到旧分支 分支切换少,任务大多是一次性构建
Clean Build Clean Build 后会重复构建相同目标 主要依赖普通增量构建
Runner 生命周期 工作目录和缓存目录可持久化 每次任务结束后销毁整个环境
构建参数 Scheme、SDK、架构和编译参数稳定 参数按任务动态变化
磁盘条件 有容量监控和清理策略 共享磁盘空间紧张,无法隔离账户
发布任务 可保留无缓存发布基线 所有发布任务都依赖同一缓存状态

表格只能帮助你筛选测试对象,不能替代命中验证。只要缓存无法在后续任务中保留,Compilation Caching 的理论收益就可能在 Runner 重建后消失;只要构建参数变化导致输入集合不同,缓存目录存在也不意味着会命中。

存储生命周期与节点边界

持久化节点、临时 Runner 与共享节点

持久化远程 Mac 可以保留工作目录、DerivedData 和相关缓存,更适合多分支开发、重复构建和长期运行的自托管任务。但你必须监控磁盘增长、账户隔离、缓存归属和清理后的恢复能力。

临时 Runner 每次任务都从干净环境开始,初始状态更容易统一,也适合强调复现性的任务。不过,缓存通常难以跨任务保留。启用前必须确认所谓“缓存复用”是否真的跨越了任务生命周期。

多人共享节点 还要额外考虑缓存污染。不同项目、账户或工具链共用一个节点时,缓存目录权限、路径、分支和清理策略可能互相影响。不要把“目录存在”当作“缓存安全可复用”的证明。

你可以结合 远程 Mac 构建节点的存储与重启验收 检查工作目录、重启策略和磁盘交付方式。若节点重启后会自动重置工作区,就应把它按临时 Runner 处理,而不是按持久化缓存节点估算收益。

清理与停止条件

清理不能简单写成“定期删除缓存”。你至少要记录:

  • 缓存目录的增长趋势;
  • 最近一次命中时间;
  • 目录对应的项目、分支和工具链;
  • 清理后第一次构建的耗时;
  • 清理后第二次相同输入构建的耗时;
  • 清理是否影响归档、测试和发布任务。

出现以下任一情况,应暂停扩大缓存范围:

  • 磁盘压力开始影响编译、模拟器或归档;
  • 缓存诊断与构建结果不一致;
  • 无缓存构建失败,说明项目可能依赖隐式产物;
  • 多个账户之间出现权限或路径污染;
  • 重启后缓存保留状态与预期不符;
  • 发布任务只能在“有缓存”状态下成功。

Build Settings 会影响源码编译、链接、调试信息生成以及最终打包,因此缓存验收不能只覆盖编译命令,还要覆盖归档和发布流程。

发布复现与灰度范围

三条发布基线

Compilation Caching 进入共享 CI 后,建议保留三条基线:

  1. 缓存开启基线:观察常规分支构建的命中和耗时。
  2. 缓存关闭基线:判断真实加速来源,也作为异常时的快速复测路径。
  3. 全新克隆基线:验证项目没有依赖某个节点上残留的隐式产物。

发布归档不应只依赖开发分支的加速结果。你需要在关闭缓存的情况下完成一次全新克隆、依赖恢复、编译、测试和归档;再在开启缓存的情况下重复相同流程,比较产物一致性和失败记录。

Apple 的性能测试文档强调了固定测试输入、记录结果和识别回归的重要性。这个思路同样适合 CI 缓存验收:固定提交和构建参数,保存日志与计时结果,并为异常变化设置停止条件。Apple 性能测试文档

如果项目使用显式模块依赖,还应关注不同模块的构建选项是否一致。模块选项差异可能导致看似相同的输入无法复用相同结果;这时应先检查构建设置和模块依赖关系,再判断缓存是否失效。

灰度放量清单

  • [ ] 固定项目提交、Scheme、SDK、架构和构建参数。
  • [ ] 记录节点型号、macOS 版本、Xcode 版本和 Runner 工作目录策略。
  • [ ] 为 Compilation Caching 启用诊断信息,并保存完整构建日志。
  • [ ] 使用 xcodebuild -showBuildTimingSummary 输出构建阶段计时。
  • [ ] 分别执行首次构建、相同输入复跑和历史分支切回。
  • [ ] 单独记录编译、链接、签名、测试、脚本和依赖下载耗时。
  • [ ] 检查缓存目录、DerivedData 和依赖下载缓存的大小变化。
  • [ ] 重启节点后重复相同输入构建,确认缓存是否仍在。
  • [ ] 完成一次无缓存全新克隆构建。
  • [ ] 完成一次无缓存发布归档,并保存结果作为回滚基线。
  • [ ] 为共享节点设置关闭入口和无缓存复测路径。
  • [ ] 只有在命中证据、构建结果和磁盘状态均稳定后扩大灰度范围。

决策评分与回退路径

你可以用 5 个维度做内部评分,每项从 0 到 2 分

  • 输入重复度:相同源文件是否经常被再次编译;
  • 节点持久性:缓存目录能否跨任务、跨重启保留;
  • 参数稳定性:Scheme、SDK 和编译选项是否稳定;
  • 证据完整度:是否有诊断信息和 Build Timing Summary;
  • 运维可控性:是否能监控容量、清理缓存和执行无缓存回测。

建议按结果处理:

  • 8~10 分:可在持久化远程 Mac CI 节点灰度启用。
  • 5~7 分:只对开发分支或非发布任务启用,继续收集数据。
  • 0~4 分:暂缓启用,先解决 Runner 生命周期、参数漂移或磁盘管理问题。

这个评分是上线门槛,不是性能承诺。最终判断仍应回到单位成功构建的时间、失败重试次数、磁盘维护成本和发布复现能力,而不是缓存目录是否存在。

如果你正在规划节点容量,可以参考 Mac mini M4 价格与服务器方案指南,把持久化磁盘、重启机制和多任务隔离纳入总成本,而不是只比较处理器参数。

常见问题

Clean Build 的缓存价值

Clean Build 并不自动保证缓存命中,但它属于值得测试的工作流。你要确认 Clean Build 后重新处理的源文件输入是否与之前一致,并用诊断日志和构建计时证明结果被复用。若 Clean Build 后仍需执行大量链接、签名和测试,总流水线时间可能不会明显变化。

xcodebuild 的命中确认

在 CI 中,xcodebuild 负责执行任务,-showBuildTimingSummary 负责输出阶段计时;两者结合才能定位编译阶段是否变化。诊断设置用于确认缓存参与了哪些任务,Build Timing Summary 用于确认这些任务是否真的影响了编译耗时。缺少其中一项时,不应仅凭总时长判断。

Runner 重启后的状态

Runner 重启后能否保留 Compilation Caching,取决于缓存所在磁盘、节点重置脚本和账户目录策略。持久化节点可能保留缓存,但仍需实测;临时节点如果重启后重新初始化系统或工作目录,则不能把缓存收益计入长期模型。

磁盘清理边界

清理前先记录目录、归属项目和最近命中情况,再按项目或工具链进行定向清理。清理完成后必须做无缓存构建,验证项目没有依赖残留产物。共享节点还要检查权限、并发任务和其他项目是否受到影响。

多分支项目的默认策略

多分支项目不建议未经测试就全量开启。若分支之间反复切换、输入高度重复,并且节点可以持久化缓存,可以先让开发分支进入灰度;发布归档保留独立的无缓存基线,确认复现和回滚都没有问题后再扩大范围。

对比你当前的 CI 方案与 MacDate 的远程 Mac 方案时,真正需要关注的不是“缓存开关”本身,而是节点能否长期保留工作目录、重启后状态是否可验收,以及磁盘清理和账户隔离是否可控。临时 Runner 的缓存经常随环境销毁,Linux 云主机又无法直接替代需要 Xcode 和 macOS 工具链的构建任务;如果你自行维护 Mac mini,还要承担硬件在线、远程接入和故障恢复成本。

如果你只是需要临时扩展构建容量、验证 Compilation Caching,或先搭建一台可持久化的远程 Mac CI 节点,租赁 MacDate 的真实 Mac 主机会比立刻购买硬件更容易做小范围验证。反过来,长期稳定的重负载、必须接入物理设备或需要完全掌控硬件的场景,仍应优先评估自购 Mac。

最后更新于 2026 年 9 月 3 日,设置名称、Xcode 版本和适用范围核对自本文引用的 Apple 官方 Release Notes、系统要求、Build Settings Reference、构建计时和性能测试文档。Apple 调整缓存默认行为、发布新的 Xcode 稳定版或节点交付方式变化时,应重新执行同项目对照测试。