Bazel 对平台和工具链提供精细的支持。将此功能与实际项目集成需要代码所有者、规则维护者和核心 Bazel 开发者之间的密切合作。
本页面总结了平台的目的,并展示了如何使用平台进行构建。
总结:Bazel 的平台和工具链 API 可用,但在所有语言规则、select()
和其他旧版引用更新之前,它们无法在所有位置正常运行。这项工作仍在进行中。最终,所有 build 都将基于平台。
请阅读下文,了解您的 build 属于哪个类别。
如需查看更正式的文档,请参阅:
背景
引入了平台和工具链,以标准化软件项目如何以不同的机器为目标平台并使用正确的语言工具进行构建。
这是 Bazel 中相对较新的功能。它的灵感来自于观察到语言维护人员已经在以临时、不兼容的方式执行此操作。例如,C++ 规则使用 --cpu
和 --crosstool_top
来设置 build 的目标 CPU 和 C++ 工具链。这两种方式都无法正确模拟“平台”。过去尝试这样做会导致构建不顺畅且不准确。这些标志也不控制 Java 编译,后者已通过 --java_toolchain
发展出自己的独立接口。
Bazel 适用于大型多语言多平台项目。这就要求我们为这些概念提供更具原则性的支持,包括鼓励语言和项目互操作性的清晰 API。这些新 API 就是为此而设计的。
迁移
平台和工具链 API 仅在项目实际使用时才有效。这并非易事,因为项目的规则逻辑、工具链、依赖项和 select()
必须支持它们。这需要仔细规划迁移顺序,以确保所有项目及其依赖项正常运行。
例如,Bazel 的 C++ 规则支持平台。但 Apple 规则不会。您的 C++ 项目可能不关心 Apple。但其他平台可能可以。因此,目前尚不适合为所有 C++ build 全局启用平台。
本页的其余部分将介绍此迁移序列,以及您的项目何时可以加入此序列。
目标
当所有项目都以以下形式构建时,Bazel 的平台迁移即完成:
bazel build //:myproject --platforms=//:myplatform
这意味着:
- 项目使用的规则可以从
//:myplatform
推断出正确的工具链。 - 项目依赖项使用的规则可以从
//:myplatform
推断出正确的工具链。 - 或者,取决于您的项目支持
//:myplatform
或者,您的项目支持旧版 API(例如--crosstool_top
)。 //:myplatform
引用了CPU
、OS
和其他支持自动跨项目兼容性的通用概念的 [通用声明][Common Platform Declaration]{: .external}。- 所有相关项目
select()
都了解//:myplatform
所隐含的机器属性。 //:myplatform
定义在一个清晰且可重用的位置:如果平台是项目独有的,则在项目的代码库中;否则,在所有可能使用此平台的项目都可以找到的位置。
一旦实现此目标,旧版 API 就会被移除。这样一来,项目选择平台和工具链的方式就会标准化。
我是否应该使用平台?
如果您只是想构建或交叉编译项目,则应遵循项目的官方文档。
如果您是项目、语言或工具链维护人员,最终会希望支持新的 API。您是等待全球迁移完成,还是选择提前加入,取决于您的具体价值 / 成本需求:
值
- 您可以
select()
或选择您真正关心的属性的工具链,而不是像--cpu
这样的硬编码标志。例如,多个 CPU 可以支持同一指令集。 - 更正确的 build。如果您在上述示例中将
select()
与--cpu
搭配使用,然后添加支持相同指令集的新 CPU,则select()
无法识别新 CPU。但平台上的select()
仍然准确。 - 更简单的用户体验。所有项目都了解:
--platforms=//:myplatform
。无需在命令行中添加多个特定于语言的标志。 - 更简单的语言设计。所有语言都共用一个用于定义工具链、使用工具链以及为平台选择合适工具链的通用 API。
- 如果目标与目标平台不兼容,则可以在构建和测试阶段跳过目标。
费用
- 尚不支持平台的依赖项目可能无法自动与您的项目搭配使用。
- 要让它们正常运行,可能需要进行额外的临时维护。
- 新 API 和旧 API 共存时,需要更仔细地引导用户,以免造成混淆。
- 常见属性(如
OS
和CPU
)的规范定义仍在不断发展,可能需要额外的初始贡献。 - 特定于语言的工具链的规范定义仍在不断发展,可能需要额外的初始贡献。
API 审核
platform
是一组constraint_value
目标:
platform(
name = "myplatform",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:arm",
],
)
constraint_value
是一种机器属性。相同“类型”的值会归类到同一个 constraint_setting
下:
constraint_setting(name = "os")
constraint_value(
name = "linux",
constraint_setting = ":os",
)
constraint_value(
name = "mac",
constraint_setting = ":os",
)
toolchain
是 Starlark 规则。其属性声明了语言的工具(例如 compiler =
"//mytoolchain:custom_gcc"
)。其提供程序会将此信息传递给需要使用这些工具进行构建的规则。
工具链会声明其可以定位的机器的 constraint_value
(target_compatible_with = ["@platforms//os:linux"]
) 以及其工具可以运行的机器 (exec_compatible_with = ["@platforms//os:mac"]
)。
构建 $ bazel build //:myproject --platforms=//:myplatform
时,Bazel 会自动选择可在构建机器上运行并为 //:myplatform
构建二进制文件的工具链。这称为“工具链解析”。
可用的工具链集可以在 WORKSPACE
中通过 register_toolchains
注册,也可以在命令行中通过 --extra_toolchains
注册。
如需深入了解,请点击此处。
状态
当前平台支持情况因语言而异。Bazel 的所有主要规则都在迁移到平台。不过,此过程需要一些时间。这主要有以下三个原因:
必须更新规则逻辑,以从新的工具链 API (
ctx.toolchains
) 获取工具信息,并停止读取旧版设置(如--cpu
和--crosstool_top
)。这相对比较简单。工具链维护人员必须定义工具链,并让用户可以访问这些工具链(在 GitHub 代码库和
WORKSPACE
条目中)。从技术上讲,这很简单,但必须以智能方式进行整理,才能保持轻松的用户体验。此外,还需要平台定义(除非您构建的目标平台与 Bazel 运行的平台相同)。一般来说,项目应定义自己的平台。
现有项目必须迁移。
select()
和过渡效果也必须迁移。这是最大的挑战。对于多语言项目来说,这尤其具有挑战性(如果所有语言都无法读取--platforms
,项目可能会失败)。
如果您要设计新的规则集,则必须从一开始就支持平台。这会自动使您的规则与其他规则和项目兼容,随着平台 API 变得越来越普及,这种兼容性也会越来越有价值。
通用平台属性
应在标准、集中的位置声明项目通用的平台属性,例如 OS
和 CPU
。这有助于实现跨项目和跨语言兼容性。
例如,如果 MyApp 在 constraint_value
@myapp//cpus:arm
上有 select()
,而 SomeCommonLib 在 @commonlib//constraints:arm
上有 select()
,则它们会以不兼容的条件触发各自的“准备”模式。
全局通用属性在 @platforms
代码库中声明(因此,上述示例的规范标签为 @platforms//cpu:arm
)。语言通用属性应在其各自语言的代码库中声明。
默认平台
一般来说,项目所有者应定义明确的平台来描述他们要构建的机器类型。然后,使用 --platforms
触发这些测试。
如果未设置 --platforms
,Bazel 会默认使用表示本地 build 机器的 platform
。此属性会在 @local_config_platform//:host
自动生成,因此无需明确定义。它将本地机器的 OS
和 CPU
与 @platforms
中声明的 constraint_value
相关联。
C++
当您设置 --incompatible_enable_cc_toolchain_resolution
时,Bazel 的 C++ 规则会使用平台来选择工具链 (#7260)。
这意味着您可以配置具有以下特征的 C++ 项目:
bazel build //:my_cpp_project --platforms=//:myplatform
而不是旧版:
bazel build //:my_cpp_project` --cpu=... --crosstool_top=... --compiler=...
如果您的项目是纯 C++ 项目,并且不依赖于非 C++ 项目,那么只要您的 select
和过渡兼容,您就可以安全地使用平台。如需了解更多指导信息,请参阅 #7260 和配置 C++ 工具链。
此模式默认处于未启用状态。这是因为 Apple 项目仍使用 --cpu
和 --crosstool_top
配置 C++ 依赖项(示例)。因此,这取决于 Apple 规则是否迁移到平台。
Java
Bazel 的 Java 规则使用平台。
此标志取代了旧版标志 --java_toolchain
、--host_java_toolchain
、--javabase
和 --host_javabase
。
如需了解如何使用配置标志,请参阅 Bazel 和 Java 手册。如需了解详情,请参阅设计文档。
如果您仍在使用旧版标志,请按照问题 #7849 中的迁移流程操作。
Android
当您设置 --incompatible_enable_android_toolchain_resolution
时,Bazel 的 Android 规则会使用平台来选择工具链。
此功能默认处于停用状态。但迁移正在顺利进行。
Apple
Bazel 的 Apple 规则尚不支持用于选择 Apple 工具链的平台。
它们也不支持平台启用的 C++ 依赖项,因为它们使用旧版 --crosstool_top
来设置 C++ 工具链。在迁移完成之前,您可以将 Apple 项目与启用平台的 C++ 混合使用,并使用平台映射(示例)。
其他语言
如果您要为新语言设计规则,请使用平台来选择语言的工具链。如需了解详细的演练,请参阅工具链文档。
select()
项目可以select()
constraint_value
目标,但不能select()
完整平台。这是有意为之,目的是让 select()
尽可能支持各种机器。具有 ARM
特定来源的库应支持所有基于 ARM
的机器,除非有理由进行更具体的指定。
如需选择一个或多个 constraint_value
,请使用:
config_setting(
name = "is_arm",
constraint_values = [
"@platforms//cpu:arm",
],
)
这相当于在 --cpu
上以传统方式进行选择:
config_setting(
name = "is_arm",
values = {
"cpu": "arm",
},
)
如需了解更多详情,请点击此处。
--cpu
、--crosstool_top
等设备上的 select
不理解 --platforms
。将项目迁移到平台时,您必须将它们转换为 constraint_values
,或者使用平台映射在迁移窗口期间同时支持这两种样式。
转场效果
Starlark 转换会更改 build 图的部分标志。如果您的项目使用的过渡会设置 --cpu
、--crossstool_top
或其他旧版标志,则读取 --platforms
的规则不会看到这些更改。
将项目迁移到平台时,您必须将 return { "//command_line_option:cpu": "arm" }
等更改转换为 return {
"//command_line_option:platforms": "//:my_arm_platform" }
,或者使用平台映射在迁移窗口期间同时支持这两种样式。
如何使用当今的平台
如果您只是想构建或交叉编译项目,则应遵循项目的官方文档。语言和项目维护人员可以自行决定如何以及何时与平台集成,以及集成可带来的价值。
如果您是项目、语言或工具链维护人员,并且您的 build 默认不使用平台,那么除了等待全局迁移之外,您还有以下三种选择:
为项目的语言(如果有)启用“使用平台”标志,并进行所需的任何测试,以查看您关心的项目是否正常运行。
如果您关注的项目仍依赖于
--cpu
和--crosstool_top
等旧版标志,请将这些标志与--platforms
一起使用:bazel build //:my_mixed_project --platforms==//:myplatform --cpu=... --crosstool_top=...
这种方法需要一定的维护成本(您必须手动确保设置一致)。但如果没有叛逆过渡,这应该可以正常运行。
编写平台映射,通过将
--cpu
样式的设置映射到相应平台,反之亦然,来支持这两种样式。
平台映射
平台映射是一种临时 API,可在旧版逻辑的弃用窗口期内,让平台驱动型逻辑和旧版驱动型逻辑共存于同一 build 中。
平台映射是指从 platform()
到一组对应的旧版标志的映射,反之亦然。例如:
platforms:
# Maps "--platforms=//platforms:ios" to "--cpu=ios_x86_64 --apple_platform_type=ios".
//platforms:ios
--cpu=ios_x86_64
--apple_platform_type=ios
flags:
# Maps "--cpu=ios_x86_64 --apple_platform_type=ios" to "--platforms=//platforms:ios".
--cpu=ios_x86_64
--apple_platform_type=ios
//platforms:ios
# Maps "--cpu=darwin --apple_platform_type=macos" to "//platform:macos".
--cpu=darwin
--apple_platform_type=macos
//platforms:macos
Bazel 使用此功能来保证所有设置(包括基于平台的设置和旧版设置)在整个 build 过程中(包括通过转换)始终保持一致。
默认情况下,Bazel 会从工作区根目录中的 platform_mappings
文件读取映射。您还可以设置 --platform_mappings=//:my_custom_mapping
。
如需了解完整详情,请点击此处。
问题
如需有关迁移时间表的一般支持和帮助,请发送电子邮件至 bazel-discuss@googlegroups.com 或与相应规则的所有者联系。
如需讨论平台/工具链 API 的设计和发展,请发送电子邮件至 bazel-dev@googlegroups.com。