Monorepo 解决方案 — 基于 Bazel 的 Xcode 性能优化实践

背景介绍

书接上回《Monorepo 解决方案 — Bazel 在头条 iOS 的实践》,在头条工程切换至 Bazel 构建系统后,为了支持用户使用 Xcode 开发的习惯,我们使用了开源项目 Tulsi 作为生成工具,用于将 Bazel 工程转换为 Xcode 工程。但是在使用的过程中,我们发现了一些问题,其中影响较大的是,

  • Xcode 工程卡顿:对于头条这种大型项目来说,Xcode 卡顿一直是本地研发的痛点问题,在切换 Bazel 构建系统之后卡顿现象明显加剧。

  • Xcode 功能支持受限:Tulsi 支持的功能有限,很多功能都年久失修,并未持续适配 Bazel 与 rules 的更新。

在做了一些前期调研后,我们发现 rules_xcodeproj 提供了更好的解决方案。rules_xcodeproj 是一个由一系列 Bazel rules 组成的开源项目,使用它可以从一个 Bazel 工程生成对应的 Xcode 工程,实现在 Xcode 中写代码同时使用 Bazel 进行真正的构建任务,相比于 Tulsi,rules_xcodeproj 在以下几个方面有着更为明显的优势。

  • Xcode 工程更加流畅: 头条工程迁移到 rules_xcodeproj 后,工程首次冷启、二次启动和文件增删操作的时间有了明显缩短,工程卡顿情况也明显好转。

  • Xcode 功能支持度更高: rules_xcodeproj 对 Xcode 的支持更全面(包括单元测试、SwiftUI Previews),能够更好地满足我们的需求。

  • 社区更加活跃:随着 rules_xcodeproj 在 2023 年 2 月份发布正式版,Tulsi 项目也正式宣布停止维护,这意味着对于新版本的 Bazel,Tulsi 将不再提供适配和支持;同时 rules_xcodeproj 几乎每月都会更新一个中版本,对于后续适配 Bazel 更新的成本会更低。

  • 更符合 BitSky 的演进路线:由 Bazel 驱动的工程生成方式更符合 BitSky 的 Bazel Native 演进路线,可以完全在 Bazel 环境下生成工程。

因此,我们将 Xcode 生成工具从 Tulsi 迁移到了 rules_xcodeproj,并对 BitSky 工具链进行了适配。适配过程中,我们在修复 rules_xcodeproj 索引问题的同时,对工程结构进行了一些优化,进一步提升了工程流畅度。头条 iOS 工程的测试数据如下:

测试设备 MacBook Pro,芯片 M1 Pro,内存 32GB

ps. 本文介绍均基于 rules_xcodeproj 1.4.0 版本,build with bazel 模式

pps. 由于 Xcode 主线程的卡顿较难监测,此处用主动操作的执行时间衡量流畅度


Tulsi rules_xcodeproj
工程首次冷启 47s 16s
二次启动 33s 12s
文件操作 新增 20s
删除 23s
新增 8s
删除 6s

下面来看下我们具体做的适配工作。

适配过程

从 Tulsi 迁移到 rules_xcodeproj 后,我们发现 Xcode 卡顿有明显改善,仔细分析发现 Tulsi 工程的卡顿主要有两方面原因:

  1. 头条工程中组件数量多、依赖关系复杂:Tulsi 的索引方案需要 Xcode Target 之间保留这些依赖关系,但这些依赖关系并不会被 Xcode 构建消费,却增加了 Xcode 对工程进行解析和计算的成本。

图中 Pod X_A 与 Pod X_B 为 Pod X 分别在 App A 与 App B 下被引用的 Target

4ec246b5859f3a8f8259299f78a27790.png
  1. 全源码构建:我们在切换 Bazel 时还推进了工程的全源码构建,源码数量大幅增加,也给索引任务带来更大的压力。

接下来详细说明整个分析和适配过程,带大家更全面地了解我们结合 rules_xcodeproj 在 Xcode 背后做了什么。

在 Xcode 中开发时主要会用到三部分功能:构建、索引和调试。而 Xcode 并不能直接理解 Bazel 项目的工程文件(BUILD 和 WORKSPACE),所以我们需要通过工具(rules_xcodeproj 或 Tulsi)将 Bazel 的工程文件转换为 Xcode 可以理解的 .xcodeproj来支持这些功能正常工作。

各功能的适配点如下表所示。

ae4f2b66f0acc6128c5367818f006120.png

rules_xcodeproj 原生方案的调试模块基本能正常工作,而索引和构建两个模块中我们对原生方案的改造较大,因此本文主要对这两个模块进行展开介绍。

索引

前面提到支持 Xcode 索引功能需要提供各个源文件的编译参数,rules_xcodeproj 实现这一点的工作流程是:

  1. rules_xcodeproj 在 Bazel 的分析阶段获取到源码文件和编译参数;

  2. 用这些信息创建 Xcode Target 的 Compile Sources 和 Build Setting 产出工程文件 .xcodeproj

  3. Xcode 加载工程文件,获取源码文件对应的索引参数,调用 clang 或 swiftc 执行索引命令。

迁移过程中我们注意到 rules_xcodeproj 工程的索引在多 Target 共用源文件的场景存在语法高亮异常的问题,对比 Tulsi 工程的处理方式后我们得出两个结论:

  • 索引异常是由于 rules_xcodeproj 移除了所有 Library Target 间的依赖导致的;

  • Tulsi 工程中 Library Target 间的依赖关系正是导致 Tulsi 工程更为卡顿的关键原因。

后文会先分析依赖关系在索引中发挥的作用,以及 rules_xcodeproj 如何处理依赖关系移除带来的问题&

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值