本页介绍了如何使用 Bazel 构建或测试 Xcode 项目。它 介绍了 Xcode 和 Bazel 之间的区别,并提供了将 Xcode 项目转换为 Bazel 项目的步骤 。此外,它还提供了 问题排查解决方案,以解决常见错误。
Xcode 和 Bazel 之间的区别
Bazel 要求您通过构建规则显式指定每个构建目标及其 依赖项,以及相应的构建设置。
Bazel 要求项目所依赖的所有文件都存在于工作区目录中,或者在
WORKSPACE文件中指定为导入项。使用 Bazel 构建 Xcode 项目时,
BUILD文件将成为 事实来源。如果您在 Xcode 中处理项目,则每次更新BUILD文件时,都必须使用 rules_xcodeproj 生成与BUILD文件匹配的新版 Xcode 项目。对BUILD文件 进行某些更改(例如向目标添加依赖项)不需要重新生成 项目,这可以加快开发速度。如果您不使用 Xcode,则bazel build和bazel test命令会提供构建和测试功能 但存在一些限制,本指南稍后会对此进行介绍。
准备工作
在开始之前,请执行以下操作:
如果您不熟悉 Bazel 及其概念,请完成 iOS 应用教程。您应该了解 Bazel 工作区,包括
WORKSPACE和BUILD文件,以及 目标、构建规则和 Bazel 软件包的概念。分析并了解项目的依赖项。
分析项目依赖项
与 Xcode 不同,Bazel 要求您显式声明所有依赖项,以便
在 BUILD 文件中为每个目标。
如需详细了解外部依赖项,请参阅 使用外部依赖项。
使用 Bazel 构建或测试 Xcode 项目
如需使用 Bazel 构建或测试 Xcode 项目,请执行以下操作:
-
a. 添加应用目标
b. (可选)添加测试目标
c. 添加库目标
第 1 步:创建 WORKSPACE 文件
在新目录中创建 WORKSPACE 文件。此目录将成为 Bazel
工作区根目录。如果项目不使用任何外部依赖项,则此文件可以为
空。如果项目依赖于不在项目任何目录中的文件或软件包,请在 WORKSPACE
文件中指定这些外部依赖项。
第 2 步:(实验性)集成 SwiftPM 依赖项
如需使用 swift_bazel 将 SwiftPM 依赖项集成到 Bazel 工作区中, 您必须按照 以下教程 中所述将其转换为 Bazel 软件包。
第 3 步:创建 BUILD 文件
定义工作区和外部依赖项后,您需要
创建一个 BUILD 文件,告知 Bazel 项目的结构。在 Bazel 工作区的根目录下创建
BUILD文件,并将其配置为对项目进行
初始构建,如下所示:
提示:如需详细了解软件包和其他 Bazel 概念,请参阅 工作区、软件包和目标。
第 3a 步:添加应用目标
添加 macos_application
或 ios_application
规则目标。此目标分别构建 macOS 或 iOS 应用软件包。
在目标中,至少指定以下内容:
bundle_id- 二进制文件的软件包 ID(反向 DNS 路径,后跟应用名称)。provisioning_profile- Apple 开发者 账号中的配置文件(如果为 iOS 设备构建)。families(仅限 iOS)- 是否为 iPhone、iPad、 或两者构建应用。infoplists- 要合并到最终 Info.plist 文件中的 .plist 文件列表。minimum_os_version- 应用支持的最低 macOS 或 iOS 版本。这可确保 Bazel 使用 正确的 API 级别构建应用。
第 3b 步:(可选)添加测试目标
Bazel 的 Apple 构建规则 支持 在所有 Apple 平台上运行单元测试和界面测试。按如下方式添加测试目标:
macos_unit_test,用于在 macOS 上运行基于库和基于应用的单元测试。ios_unit_test,用于在 iOS 上构建和运行基于库的单元测试。ios_ui_test,用于在 iOS 模拟器中构建和运行界面测试。
至少为 minimum_os_version 属性指定一个值。虽然
其他封装属性(例如 bundle_identifier 和 infoplists)
默认使用最常用的值,但请确保这些默认值与项目兼容,
并根据需要进行调整。对于需要 iOS
模拟器的测试,还要将 ios_application 目标名称指定为
test_host 属性的值。
第 3c 步:添加库目标
为应用和/或测试所依赖的每个 Objective-C 库添加 objc_library
目标,并为每个 Swift 库添加 swift_library
目标。
按如下方式添加库目标:
将应用库目标作为依赖项添加到应用 目标。
将测试库目标作为依赖项添加到测试目标。
在
srcs属性中列出实现来源。在
hdrs属性中列出标头。
您可以直接在 rules_apple 示例目录中浏览各种类型应用的现有示例。例如:
如需详细了解构建规则,请参阅 适用于 Bazel 的 Apple 规则。
此时,最好测试一下构建:
bazel build //:<application_target>
第 4 步:(可选)细化构建
如果项目很大,或者随着项目的增长,请考虑将其分块为多个 Bazel 软件包。这种细化程度的提高可提供以下优势:
构建的增量性提高,
构建任务的并行化程度提高,
未来用户可以更好地维护,
更好地控制目标和软件包之间的源代码可见性。这 可以防止库中包含的实现细节泄露 到公共 API 等问题。
细化项目的提示:
将每个库放在自己的 Bazel 软件包中。从需要最少依赖项的库开始,然后逐步向上遍历依赖项树。
添加
BUILD文件并指定目标时,请将这些新目标添加到依赖于这些目标的目标的deps属性中。glob()函数不会跨越软件包边界,因此随着软件包数量 的增加,glob()匹配的文件数量会减少。向
main目录添加BUILD文件时,还要向 相应的test目录添加BUILD文件。在软件包之间强制执行健康的可见性限制。
在对
BUILD文件进行每次重大更改后构建项目,并在遇到 构建错误时修复这些错误。
第 5 步:运行构建
运行完全迁移的构建,确保构建完成且没有错误或警告。 单独运行每个应用和测试目标,以便更轻松地找到发生的任何错误的来源 。
例如:
bazel build //:my-target第 6 步:使用 rules_xcodeproj 生成 Xcode 项目
使用 Bazel 构建时,WORKSPACE 和 BUILD 文件将成为构建的事实来源
。如需让 Xcode 了解这一点,您必须使用 rules_xcodeproj 生成与 Bazel 兼容的 Xcode 项目。
问题排查
当 Bazel 与所选 Xcode 版本不同步时 (例如在应用更新时),可能会出现 Bazel 错误。如果您在使用 Xcode 时遇到错误(例如“必须指定 Xcode 版本才能使用 使用 Apple CROSSTOOL”),请尝试以下操作。
手动运行 Xcode 并接受任何条款及条件。
使用 Xcode select 指明正确的版本,接受许可,并 清除 Bazel 的状态。
sudo xcode-select -s /Applications/Xcode.app/Contents/Developersudo xcodebuild -licensebazel sync --configure
- 如果此方法不起作用,您还可以尝试运行
bazel clean --expunge。