Bazel 可以在各种硬件、操作系统和 多个不同版本的构建工具(如 链接器和编译器。为了帮助管理这种复杂性,Bazel 有一个概念 constraints 和 platforms。约束条件是指 例如 CPU 架构、在线状态或 未配备 GPU 或系统安装的编译器的版本。平台是 这些约束条件的选择集合,表示 一些环境中可用的资源
将环境建模为平台有助于 Bazel 自动选择 适当 工具链 进行构建操作平台还可与 config_setting 规则写入可配置属性。
Bazel 可识别平台可以提供服务的三种角色:
- 主机 - 运行 Bazel 本身的平台。
- Execution - 构建工具在此平台上执行构建操作 生成中间输出和最终输出。
- 目标 - 最终输出驻留和执行的平台。
Bazel 支持以下关于平台的构建场景:
单平台构建(默认)- 托管平台、执行平台和目标平台 都没有变化例如,在 Ubuntu 上运行一个 Linux 可执行文件, Intel x64 CPU
交叉编译 build - 托管平台和执行平台相同,但 目标平台不同例如,在 macOS 上构建 iOS 应用 在 MacBook Pro 上运行。
多平台构建 - 主机、执行和目标平台 与众不同。
定义限制条件和平台
针对平台的可能选择空间是使用
constraint_setting
和
BUILD
文件中的 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 附带了以下特殊的平台定义:
@local_config_platform//:host
。这是自动检测到的主机平台值 -
表示针对运行 Bazel 的系统自动检测到的平台。
为构建指定平台
您可以使用以下条件为 build 指定主机和目标平台 命令行 flag:
--host_platform
- 默认值为@local_config_platform//:host
<ph type="x-smartling-placeholder">- </ph>
@local_config_platform
是用于检测主机操作系统和 CPU 并写入平台目标。- 它还创建了
@local_config_platform//:constraintz.bzl
,用于公开 一个名为HOST_CONSTRAINTS
的数组,该数组可用于其他 build 和 Starlark 文件。
--platforms
- 默认为托管平台 <ph type="x-smartling-placeholder">- </ph>
- 这意味着,如果没有设置其他标志,
@local_config_platform//: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"],
}),
)
上述内容可解释为:
- 以 macOS 为目标平台时,目标没有限制。
- 以 Linux 为目标平台时,目标没有任何限制。
- 否则,目标具有
@platforms//:incompatible
约束条件。因为@platforms//:incompatible
不属于任何平台,目标是 不兼容。
要提高约束条件的可读性,请使用
skylib 的
selects.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
检测不兼容的目标
您可以使用
IncompatiblePlatformProvider
在 bazel cquery
的 Starlark 输出中
格式来区分
从兼容设备获取不兼容的目标。
此参数可用于滤除不兼容的目标。以下示例将 仅输出兼容目标的标签。不兼容的目标包括 未打印。
$ cat example.cquery
def format(target):
if "IncompatiblePlatformProvider" not in providers(target):
return target.label
return ""
$ bazel cquery //... --output=starlark --starlark:file=example.cquery
已知问题
不兼容的目标忽略可见性 限制。