平台

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

Bazel 可以在各种硬件、操作系统和 多个不同版本的构建工具(如 链接器和编译器。为了帮助管理这种复杂性,Bazel 有一个概念 constraintsplatforms。约束条件是指 例如 CPU 架构、在线状态或 未配备 GPU 或系统安装的编译器的版本。平台是 这些约束条件的选择集合,表示 一些环境中可用的资源

将环境建模为平台有助于 Bazel 自动选择 适当 工具链 进行构建操作平台还可与 config_setting 规则写入可配置属性

Bazel 可识别平台可以提供服务的三种角色:

  • 主机 - 运行 Bazel 本身的平台。
  • Execution - 构建工具在此平台上执行构建操作 生成中间输出和最终输出。
  • 目标 - 最终输出驻留和执行的平台。

Bazel 支持以下关于平台的构建场景:

  • 单平台构建(默认)- 托管平台、执行平台和目标平台 都没有变化例如,在 Ubuntu 上运行一个 Linux 可执行文件, Intel x64 CPU

  • 交叉编译 build - 托管平台和执行平台相同,但 目标平台不同例如,在 macOS 上构建 iOS 应用 在 MacBook Pro 上运行。

  • 多平台构建 - 主机、执行和目标平台 与众不同。

定义限制条件和平台

针对平台的可能选择空间是使用 constraint_settingBUILD 文件中的 constraint_value 规则。 constraint_setting 用于创建新维度,而 constraint_value 可为给定维度创建新值;一起 来有效定义枚举及其可能值。例如,以下 BUILD 文件的代码段引入了针对系统的 glibc 版本的限制条件 两个可能的值。

constraint_setting(name = "glibc_version")

constraint_value(
    name = "glibc_2_25",
    constraint_setting = ":glibc_version",
)

constraint_value(
    name = "glibc_2_26",
    constraint_setting = ":glibc_version",
)

您可以在 工作区。这些内容由标签引用,并且通常公开范围 控件。如果可见性允许,您可以通过以下方法扩展现有限制条件设置: 定义您自己的价值

platform 规则引入了一个新平台,该平台具有 限制条件值的特定选择。通过 会创建名为 linux_x86 的平台,并说明该平台描述的 环境 glibc 2.25 版。(有关 Bazel 内置限制条件的详情,请参阅下文。)

platform(
    name = "linux_x86",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":glibc_2_25",
    ],
)

普遍有用的限制条件和平台

为了保持生态系统的一致性,Bazel 团队维护了一个 最常用 CPU 架构和运算的 系统。这些都位于 https://github.com/bazelbuild/platforms.

Bazel 附带了以下特殊的平台定义: @platforms//host(别名为 @bazel_tools//tools:host_platform)。这是 自动检测到的主机平台值 - 表示针对运行 Bazel 的系统自动检测到的平台。

为构建指定平台

您可以使用以下条件为 build 指定主机和目标平台 命令行 flag:

  • --host_platform - 默认值为 @bazel_tools//tools:host_platform
    • 此目标的别名为由代码库支持的 @platforms//host 规则检测主机操作系统和 CPU 并写入平台目标。
    • 此外,还有 @platforms//host:constraints.bzl,用于公开 一个名为 HOST_CONSTRAINTS 的数组,该数组可用于其他 build 和 Starlark 文件。
  • --platforms - 默认为托管平台 <ph type="x-smartling-placeholder">
      </ph>
    • 这意味着,如果未设置其他标志, @platforms//host 是目标平台。
    • 如果设置了 --host_platform 而非 --platforms--host_platform 既是主机平台,也是目标平台。

跳过不兼容的目标

在针对特定目标平台构建应用时,通常希望跳过 这些目标永远无法在该平台上发挥作用。例如,您的 Windows 设备 在进行构建时,驱动程序可能会产生大量编译器错误 运行 //... 的 Linux 机器。使用 target_compatible_with 属性告知 Bazel 您的代码具有哪些目标平台限制。

此属性最简单的用法可将目标限制为单个平台。 系统不会针对无法满足所有 限制条件。以下示例将 win_driver_lib.cc 限制为 64 位 窗户。

cc_library(
    name = "win_driver_lib",
    srcs = ["win_driver_lib.cc"],
    target_compatible_with = [
        "@platforms//cpu:x86_64",
        "@platforms//os:windows",
    ],
)

:win_driver_lib 兼容在 64 位 Windows 和 不能完全兼容不兼容具有传递性。任何目标 间接依赖于不兼容的目标本身会被视为 不兼容。

何时跳过目标?

如果目标被认为不兼容,并包含在 作为目标模式扩展的一部分进行构建例如,以下两个 调用会跳过在目标模式扩展中找到的任何不兼容的目标。

$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all

test_suite 中不兼容的测试包括 如果在命令行中指定了 test_suite,并且使用 --expand_test_suites。 换句话说,命令行上的 test_suite 目标的行为类似于 :all...。使用 --noexpand_test_suites 可防止展开并导致 不兼容测试的 test_suite 也表示为不兼容。

在命令行上明确指定不兼容的目标会导致 错误消息和构建失败。

$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully

如果存在以下情况,系统会以静默方式跳过不兼容的显式目标: --skip_incompatible_explicit_targets已启用。

更具表现力的限制

为了更灵活地表示约束条件,请使用 @platforms//:incompatible constraint_value 无法满足平台要求

select() 与以下产品结合使用 @platforms//:incompatible 来表示更复杂的限制。对于 可以用它来实现基本的 OR 逻辑。以下代码标记了一个库 但不兼容 macOS 和 Linux。

cc_library(
    name = "unixish_lib",
    srcs = ["unixish_lib.cc"],
    target_compatible_with = select({
        "@platforms//os:osx": [],
        "@platforms//os:linux": [],
        "//conditions:default": ["@platforms//:incompatible"],
    }),
)

上述内容可解释为:

  1. 以 macOS 为目标平台时,目标没有限制。
  2. 以 Linux 为目标平台时,目标没有任何限制。
  3. 否则,目标具有 @platforms//:incompatible 约束条件。因为 @platforms//:incompatible 不属于任何平台,目标是 不兼容。

要提高约束条件的可读性,请使用 skylibselects.with_or()

您可以使用类似的方式表示反向兼容性。以下示例 描述了一个与除 ARM 以外的所有内容都兼容的库。

cc_library(
    name = "non_arm_lib",
    srcs = ["non_arm_lib.cc"],
    target_compatible_with = select({
        "@platforms//cpu:arm": ["@platforms//:incompatible"],
        "//conditions:default": [],
    }),
)

使用 bazel cquery 检测不兼容的目标

您可以使用 IncompatiblePlatformProviderbazel cqueryStarlark 输出中 格式来区分 从兼容设备获取不兼容的目标。

此参数可用于滤除不兼容的目标。以下示例将 仅输出兼容目标的标签。不兼容的目标包括 未打印。

$ cat example.cquery

def format(target):
  if "IncompatiblePlatformProvider" not in providers(target):
    return target.label
  return ""


$ bazel cquery //... --output=starlark --starlark:file=example.cquery

已知问题

不兼容的目标忽略可见性 限制