如何在 Bazel 中进行配置和变体处理?

And*_*eas 3 bazel

一遍又一遍地阅读 Bazel 文档,没有什么新鲜感,但我似乎无法掌握如何为本机以外的变体(例如--cpu和 )设置配置和变体--compilation_mode

为了解释我对配置和变体的含义,请考虑此配置行、变体点列和变体单元格的表(制作此表,希望它至少具有抽象意义):

有硬件模块 X 接口已连接 快速失败
客户配置1 是的 以太网 是的
客户配置2 是的 USB 是的
客户配置3 USB
调试硬件配置 串口 是的

从 Bazel 用户的角度来看:

  • 默认情况下,所有目标都应该可针对所有配置构建
    • 无法在添加配置时到处添加“客户配置 X”
    • 配置特定组件应该能够明确声明它特定于哪个配置
      • 我认为这就是constraint_value的用途
  • 规则应根据配置添加标志
    • 例如-DVARIANT_POINT_CONNECTED_ETH用于以太网连接和-DVARIANT_POINT_CONNECTED_USBUSB 连接
  • 我想要一个简单的构建命令来构建/测试/运行单个配置
    • 就像是bazel build //my/target --//:configuration=debughw
    • 认为skylark 配置文档中有一些关于它的内容,但没有看到如何从示例转到使用constraint_values和select()规则

Bri*_*man 7

您正在寻找平台构建设置(您首先找到的)更适合独立的配置部分,其中以任何排列设置它们都是有用的,而不是平台将所有部分捆绑在一起。然后,生成的设置和约束可用于驱动编译器标志并将目标限制为某些配置。

对于你的例子,我认为这样的事情是有道理的:

constraint_setting(name = "has_x")

constraint_value(
    name = "x_v1",
    constraint_setting = ":has_x",
)

constraint_value(
    name = "x_v2",
    constraint_setting = ":has_x",
)

constraint_value(
    name = "x_none",
    constraint_setting = ":has_x",
)

constraint_setting(name = "interface")

constraint_value(
    name = "interface_usb",
    constraint_setting = ":interface",
)

constraint_value(
    name = "interface_ethernet",
    constraint_setting = ":interface",
)

constraint_value(
    name = "interface_uart",
    constraint_setting = ":interface",
)

constraint_setting(name = "failure_reporting")

constraint_value(
    name = "fail_fast",
    constraint_setting = ":failure_reporting",
)

constraint_value(
    name = "fail_bugreport",
    constraint_setting = ":failure_reporting",
)

platform(
    name = "customer_1",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":x_v1",
        ":interface_ethernet",
        ":fail_fast",
    ],
)

platform(
    name = "customer_2",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":x_v1",
        ":interface_usb",
        ":fail_fast",
    ],
)

platform(
    name = "customer_3",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":x_none",
        ":interface_usb",
        ":fail_bugreport",
    ],
)

platform(
    name = "debug_hw",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":x_none",
        ":interface_uart",
        ":fail_fast",
    ],
)
Run Code Online (Sandbox Code Playgroud)

请注意每个平台如何为每个约束指定设置。给定的编译器命令(由配置的 target创建)将仅使用一个平台。此外,即使输出相同,每个文件也会针对每个平台单独编译。平台旨在限制实际构建的约束排列。如果你想消除重复的约束,platform.parents可以让你构建平台的继承树,你不能同时使用两个平台。

target_complete_with属性目标限制为特定的约束值。默认情况下,每个目标都被认为与所有平台兼容。如果您使用target_compatible_with限制这一点,那么当您尝试显式构建不兼容的目标时,它们将会产生错误,或者如果作为通配符的一部分包含在内,则会被跳过。对于您的用例,该目标将为任何平台构建:

cc_library(
    name = "generic_linked_list",
    <etc>
)
Run Code Online (Sandbox Code Playgroud)

但这只会为customer_1和构建customer_2

cc_library(
    name = "hardware_x_driver",
    target_compatible_with = [":x_v1", ":x_v2"],
    <etc>
)

cc_library(
    name = "ethernet_driver",
    # Or you could have a separate constraint for "has ethernet hardware",
    # to use for some platforms which have the hardware but don't use it
    # as the primary interface.
    target_compatible_with = [":interface_ethernet"],
    <etc>
)
Run Code Online (Sandbox Code Playgroud)

对于不同平台使用不同的编译器标志、依赖项或大多数其他规则属性是通过select完成的。选择可以constraint_value直接读取s。所以你可以这样写:

cc_library(
    name = "selected_connection",
    copts = select({
        ":interface_usb": [ "-DVARIANT_POINT_CONNECTED_USB" ],
        ":interface_ethernet": ["-DVARIANT_POINT_CONNECTED_ETH" ],
        ":interface_uart": ["-DVARIANT_POINT_CONNECTED_UART" ],
    }),
    deps = select({
        ":interface_ethernet": [ ":ethernet_driver" ],
        "//conditions:default": [],
    }),
    <etc>
)
Run Code Online (Sandbox Code Playgroud)

请注意,如果您希望定义传播到依赖目标,请使用cc_library.defines而不是copts。此外,使用cc_library.local_defines将提供相同的非继承语义,并且还与使用不同命令行标志的编译器兼容。

指定平台的最简单方法是使用--platforms。在这种情况下,请使用类似--platforms=//:customer_1. 您可以直接在命令行上指定,或者将其放入.bazelrc 配置部分,如下所示:

build:customer_1 --platforms=//some/long/and/annoying/package:customer_1
Run Code Online (Sandbox Code Playgroud)

您将与 一起使用--config=customer_1