从 Xcode 迁移到 Bazel

报告问题 查看来源 每晚 · 7.2。 · 7.1敬上 · 7.0 · 6.5 · 6.4

本页介绍如何使用 Bazel 构建或测试 Xcode 项目。它 介绍了 Xcode 和 Bazel 之间的区别,并提供了 用于将 Xcode 项目转换为 Bazel 项目的流程。它还提供 问题排查解决方案,以解决常见错误。

Xcode 和 Bazel 之间的区别

  • Bazel 要求您明确指定每个构建目标及其 依赖项,以及通过构建规则指定的构建设置。

  • Bazel 要求项目所依赖的所有文件都存在 工作区目录中,或在 WORKSPACE 中指定为导入项 文件。

  • 使用 Bazel 构建 Xcode 项目时,BUILD 文件会成为 信息来源。如果您在 Xcode 中处理项目,则必须生成一个 使用BUILD rules_xcodeproj BUILD 文件。BUILD 文件的特定更改 例如向目标添加依赖项时就无需重新生成 项目,从而加快开发速度。如果您使用的不是 Xcode, bazel buildbazel test 命令提供构建和测试功能 不过它们具有一定的限制。

准备工作

在开始之前,请执行以下操作:

  1. 安装 Bazel(如果尚未安装)。

  2. 如果您不熟悉 Bazel 及其概念,请先完成 iOS 应用教程。您应该了解 Bazel 工作区包括 WORKSPACEBUILD 文件,以及 目标、构建规则和 Bazel 软件包的概念

  3. 分析和了解项目的依赖项。

分析项目依赖项

与 Xcode 不同,Bazel 要求您明确声明所有依赖项, BUILD 文件中的每个目标。

如需详细了解外部依赖项,请参阅 使用外部依赖项

使用 Bazel 构建或测试 Xcode 项目

要使用 Bazel 构建或测试 Xcode 项目,请执行以下操作:

  1. 创建 WORKSPACE 文件

  2. (实验性)集成 SwiftPM 依赖项

  3. 创建 BUILD 文件

    a. 添加应用目标

    b. (可选)添加测试目标

    c. 添加库目标

  4. (可选)对 build 进行细化

  5. 运行构建

  6. 使用 rules_xcodeproj 生成 Xcode 项目

第 1 步:创建 WORKSPACE 文件

在新目录中创建一个 WORKSPACE 文件。此目录会成为 Bazel 工作区根目录。如果项目不使用外部依赖项,则此文件可以是 为空。如果项目依赖的文件或软件包不属于任何 项目的目录中,请在 WORKSPACE 中指定这些外部依赖项 文件。

第 2 步:(实验性)集成 SwiftPM 依赖项

如需使用 swift_bazel 将 SwiftPM 依赖项集成到 Bazel 工作区,请执行以下操作: 您必须按照以下教程中的说明将其转换为 Bazel 软件包。

第 3 步:创建 BUILD 文件

定义工作区和外部依赖项后,您需要 创建一个 BUILD 文件,告知 Bazel 如何构建项目。创建 运行 Bazel 工作区根目录下的 BUILD 文件,并将其配置为 项目的初始 build,如下所示:

提示:要详细了解软件包和其他 Bazel 概念,请参阅 工作区、软件包和目标

第 3a 步:添加应用目标

添加macos_applicationios_application 规则目标。此目标分别构建 macOS 或 iOS 应用软件包。 在目标中,至少要指定以下内容:

  • bundle_id - 应用的软件包 ID(反向 DNS 路径,后跟应用名称) 二进制文件

  • provisioning_profile - 您的 Apple Developer 的配置文件 (如果要针对 iOS 设备设备构建应用)。

  • families(仅限 iOS)- 是否针对 iPhone、iPad 或 或者两者兼有

  • infoplists - 要合并到最终 Info.plist 文件的 .plist 文件列表。

  • minimum_os_version - 应用提供的最低 macOS 或 iOS 版本 支持。这可确保 Bazel 使用 正确的 API 级别。

第 3b 步:(可选)添加测试目标

Bazel 的 Apple 构建规则支持 在 iOS 和 macOS 上运行基于库的单元测试,以及基于应用的单元测试 在 macOS 上运行测试。适用于 iOS 上的基于应用的测试或 则 Bazel 将构建测试输出,但测试必须在 Xcode 中运行 通过使用 rules_xcodeproj 生成的项目实现。添加测试目标,如下所示:

至少应为 minimum_os_version 属性指定一个值。虽然 其他包装属性,例如 bundle_identifierinfoplists, 默认使用最常用的值,请确保这些默认值与 与项目进行协调,并根据需要进行调整。适用于需要 iOS 模拟器,还要将 ios_application 目标名称指定为 test_host 属性。

第 3c 步:添加库目标

添加 objc_library target 和 swift_library 每个 Swift 库的目标。

添加库目标,如下所示:

  • 将应用库目标作为依赖项添加到应用中 目标。

  • 将测试库目标作为依赖项添加到测试目标中。

  • srcs 属性中列出实现源代码。

  • hdrs 属性中列出标头。

您可以直接在 rules_apple 示例目录。例如:

如需详细了解构建规则,请参阅适用于 Bazel 的 Apple 规则

此时,最好测试一下 build:

bazel build //:<application_target>

第 4 步:(可选)对 build 进行精细化构建

如果项目很大,或者随着项目规模的扩大,可以考虑将项目分成多个部分 Bazel 软件包。这种增大的粒度具有以下优势:

  • 提高了构建增量

  • 提高了构建任务的并行化,

  • 为未来用户提供更好的可维护性,

  • 更好地控制源代码在目标和软件包中的可见性。这个 防止问题,例如包含实现详情的库泄露 公共 API 中。

项目精细化的技巧:

  • 将每个库放在各自的 Bazel 软件包中。先从需要 尽可能减少依赖项,并逐步遍历依赖项树。

  • 在添加 BUILD 文件并指定目标时,将这些新目标添加到 依赖于它们的目标的 deps 属性。

  • glob() 函数不会跨越软件包边界,因此 的软件包使与 glob() 匹配的文件变小。

  • BUILD 文件添加到 main 目录时,还要将 BUILD 文件添加到 相应的 test 目录。

  • 对软件包强制执行健康的可见性限制。

  • BUILD 文件每次发生重大更改后,构建项目并修复 构建错误。

第 5 步:运行构建

运行完全迁移的 build,确保其完成,没有错误或警告。 单独运行每个应用和测试目标,以便更轻松地查找源代码 检查所发生的任何错误。

例如:

bazel build //:my-target

第 6 步:使用 rules_xcodeproj 生成 Xcode 项目

使用 Bazel 构建时,WORKSPACEBUILD 文件会成为来源 真实信息为了让 Xcode 知道这一点,您必须生成一个 使用 rules_xcodeproj 且与 Bazel 兼容的 Xcode 项目。

问题排查

如果 Bazel 错误与所选 Xcode 版本不同步 例如应用更新时如果您 使用 Xcode 时遇到错误,例如“必须为 Xcode 版本指定 请使用 Apple CROSSTOOL”。

  • 手动运行 Xcode 并接受任何条款及条件。

  • 使用 Xcode select 指明正确的版本、接受许可,以及 清除 Bazel 状态

  sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
  sudo xcodebuild -license
  bazel sync --configure
  • 如果此方法不起作用,您还可以尝试运行 bazel clean --expunge