可配置的 build 属性

<ph type="x-smartling-placeholder"></ph> 报告问题 <ph type="x-smartling-placeholder"></ph> 查看来源 每晚 · 7.2 条 · 7.1敬上 · 7.0 · 6.5 · 6.4

可配置的属性(通常称为 select())是一项 Bazel 功能,可让用户切换 构建规则属性的列表

例如,这可用于自动 为架构或 功能配置的二进制文件,可在构建时自定义。

示例

# myapp/BUILD

cc_binary(
    name = "mybinary",
    srcs = ["main.cc"],
    deps = select({
        ":arm_build": [":arm_lib"],
        ":x86_debug_build": [":x86_dev_lib"],
        "//conditions:default": [":generic_lib"],
    }),
)

config_setting(
    name = "arm_build",
    values = {"cpu": "arm"},
)

config_setting(
    name = "x86_debug_build",
    values = {
        "cpu": "x86",
        "compilation_mode": "dbg",
    },
)

这声明了用于“选择”的 cc_binary它的依赖项取决于 命令行。具体来说,deps 会变为:

命令 依赖项 =
bazel build //myapp:mybinary --cpu=arm [":arm_lib"]
bazel build //myapp:mybinary -c dbg --cpu=x86 [":x86_dev_lib"]
bazel build //myapp:mybinary --cpu=ppc [":generic_lib"]
bazel build //myapp:mybinary -c dbg --cpu=ppc [":generic_lib"]

select() 充当根据以下条件选择的值的占位符 配置条件,即引用 config_setting 的标签 目标。通过在可配置属性中使用 select(),属性 在不同的条件下有效采用不同的值。

匹配必须明确:如果匹配多个条件,则选择任一条件 * 它们都解析为相同的值。例如,在 Linux x86 上运行时, {"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"},因为两个分支都解析为“hello”。 * 一个的 values 是所有其他人的严格超集。例如:values = {"cpu": "x86", "compilation_mode": "dbg"}values = {"cpu": "x86"} 的明确特化。

在以下情况下,内置条件 //conditions:default 会自动匹配: 没有其他作用

虽然此示例使用的是 deps,但 select()srcs 上也可以发挥同样的效果。 resourcescmd 和大多数其他属性。只有少量属性 是不可配置的,并带有明确注释。例如: config_setting自己的 values 属性不可配置。

select() 和依赖项

某些属性会更改所有传递依赖项的 build 参数 。例如,genruletools--cpu 更改为 运行 Bazel 的机器(由于交叉编译,Bazel 可能 而不是构建目标的 CPU)。这称为 配置转换

给定

#myapp/BUILD

config_setting(
    name = "arm_cpu",
    values = {"cpu": "arm"},
)

config_setting(
    name = "x86_cpu",
    values = {"cpu": "x86"},
)

genrule(
    name = "my_genrule",
    srcs = select({
        ":arm_cpu": ["g_arm.src"],
        ":x86_cpu": ["g_x86.src"],
    }),
    tools = select({
        ":arm_cpu": [":tool1"],
        ":x86_cpu": [":tool2"],
    }),
)

cc_binary(
    name = "tool1",
    srcs = select({
        ":arm_cpu": ["armtool.cc"],
        ":x86_cpu": ["x86tool.cc"],
    }),
)

跑步

$ bazel build //myapp:my_genrule --cpu=arm

将 build 绑定到 g_arm.srctool1x86 x86tool.cc。附加到 my_genrule 的两个 select 都使用 my_genrule 的 build 参数,其中包含 --cpu=armtools 属性会发生变化 对于 tool1 及其传递依赖项,将 --cpu 设置为 x86select tool1 使用 tool1 的构建参数,其中包括 --cpu=x86

配置条件

可配置属性中的每个键都是对 config_settingconstraint_value

config_setting 只是 预期的命令行标志设置。通过将这些内容封装在目标中, 易于维护的“标准”用户可从多个位置参考的条件。

constraint_value 支持多平台行为

内置标志

--cpu 等标志内置在 Bazel 中:构建工具本身可以理解 适用于所有项目中的所有 build。这些参数是通过 config_setting values 属性:

config_setting(
    name = "meaningful_condition_name",
    values = {
        "flag1": "value1",
        "flag2": "value2",
        ...
    },
)

flagN 是标志名称(不带 --,因此为 "cpu",而不是 "--cpu")。valueN 是该标记的预期值。如果满足以下条件,则 :meaningful_condition_name 匹配: values 中的每个条目都匹配。顺序不相关。

解析 valueN 时,就像是在命令行中设置的一样。这意味着:

  • values = { "compilation_mode": "opt" }与“bazel build -c opt”相匹配
  • values = { "force_pic": "true" }与“bazel build --force_pic=1”相匹配
  • values = { "force_pic": "0" }与“bazel build --noforce_pic”相匹配

config_setting 仅支持会影响目标行为的标志。例如: 不允许使用 --show_progress,因为 它只会影响 Bazel 向用户报告进度的方式。定位条件无法使用这项信息 标志以构建其结果。受支持的标记的确切集合 记录。实际上,大多数“有意义”的标记工作。

自定义标志

您可以使用 Starlark build 设置。与内置标志不同,这些标志 定义为构建目标,因此 Bazel 会使用目标标签来引用它们。

这些操作由 config_settingflag_values 属性:

config_setting(
    name = "meaningful_condition_name",
    flag_values = {
        "//myflags:flag1": "value1",
        "//myflags:flag2": "value2",
        ...
    },
)

行为与内置标志相同。详见此处 获取一个工作示例。

--define 是自定义标志的旧版替代语法(例如 --define foo=bar)。这可以通过 values 属性 (values = {"define": "foo=bar"}) 或 define_values 属性 (define_values = {"foo": "bar"}).仅支持向后播放 --define 兼容性。尽可能优先使用 Starlark build 设置。

valuesflag_valuesdefine_values 分别进行评估。通过 如果所有项中的所有值都匹配,则 config_setting 会匹配。

默认条件

如果没有其他条件,则匹配内置条件 //conditions:default 匹配。

因为“正好一个匹配”规则、没有匹配的可配置属性 并且没有默认条件会发出 "no matching conditions" 错误。这可以 防止意外设置导致的静默故障:

# myapp/BUILD

config_setting(
    name = "x86_cpu",
    values = {"cpu": "x86"},
)

cc_library(
    name = "x86_only_lib",
    srcs = select({
        ":x86_cpu": ["lib.cc"],
    }),
)
$ bazel build //myapp:x86_only_lib --cpu=arm
ERROR: Configurable attribute "srcs" doesn't match this configuration (would
a default condition help?).
Conditions checked:
  //myapp:x86_cpu

若要获得更清晰的错误,您可以使用 select()no_match_error 属性。

平台

虽然在命令行中指定多个标志的功能 因此每次都需要单独设置每个选项可能很繁琐 建立目标。 平台 您可以将它们整合到简单的软件包中

# myapp/BUILD

sh_binary(
    name = "my_rocks",
    srcs = select({
        ":basalt": ["pyroxene.sh"],
        ":marble": ["calcite.sh"],
        "//conditions:default": ["feldspar.sh"],
    }),
)

config_setting(
    name = "basalt",
    constraint_values = [
        ":black",
        ":igneous",
    ],
)

config_setting(
    name = "marble",
    constraint_values = [
        ":white",
        ":metamorphic",
    ],
)

# constraint_setting acts as an enum type, and constraint_value as an enum value.
constraint_setting(name = "color")
constraint_value(name = "black", constraint_setting = "color")
constraint_value(name = "white", constraint_setting = "color")
constraint_setting(name = "texture")
constraint_value(name = "smooth", constraint_setting = "texture")
constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")

platform(
    name = "basalt_platform",
    constraint_values = [
        ":black",
        ":igneous",
    ],
)

platform(
    name = "marble_platform",
    constraint_values = [
        ":white",
        ":smooth",
        ":metamorphic",
    ],
)

您可以在命令行中指定平台。它可以激活 包含平台 constraint_values 子集的 config_setting; 允许这些 config_settingselect() 表达式中匹配。

例如,如需将 my_rockssrcs 属性设置为 calcite.sh, 只需运行

bazel build //my_app:my_rocks --platforms=//myapp:marble_platform

如果没有平台,

bazel build //my_app:my_rocks --define color=white --define texture=smooth --define type=metamorphic

select() 还可以直接读取 constraint_value

constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")
sh_binary(
    name = "my_rocks",
    srcs = select({
        ":igneous": ["igneous.sh"],
        ":metamorphic" ["metamorphic.sh"],
    }),
)

这样,当您只需要config_setting 检查是否存在单个值。

平台仍处于开发阶段。请参阅 文档了解详情。

合并 select()

select 可以在同一个属性中多次出现:

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"] +
           select({
               ":armeabi_mode": ["armeabi_src.sh"],
               ":x86_mode": ["x86_src.sh"],
           }) +
           select({
               ":opt_mode": ["opt_extras.sh"],
               ":dbg_mode": ["dbg_extras.sh"],
           }),
)

select”不能出现在其他“select”中。如果您需要嵌套 selects 并且您的属性将其他目标作为值,请使用中间目标:

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":armeabi_mode": [":armeabi_lib"],
        ...
    }),
)

sh_library(
    name = "armeabi_lib",
    srcs = select({
        ":opt_mode": ["armeabi_with_opt.sh"],
        ...
    }),
)

如果您需要在多个条件匹配时匹配 select,请考虑使用 AND 链

OR 链

请考虑以下事项:

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1": [":standard_lib"],
        ":config2": [":standard_lib"],
        ":config3": [":standard_lib"],
        ":config4": [":special_lib"],
    }),
)

大多数条件都会评估相同的依赖项。但这种语法不好看 维护。最好不必重复 [":standard_lib"] 次 次。

一种选择是将该值预定义为 BUILD 变量:

STANDARD_DEP = [":standard_lib"]

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1": STANDARD_DEP,
        ":config2": STANDARD_DEP,
        ":config3": STANDARD_DEP,
        ":config4": [":special_lib"],
    }),
)

这样可以更轻松地管理依赖项。但它仍然会导致不必要的 副本。

如需获得更直接的支持,请使用以下方法之一:

selects.with_or

通过 with_or Skylibselects 模块直接支持在 select 内使用 OR 条件:

load("@bazel_skylib//lib:selects.bzl", "selects")
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = selects.with_or({
        (":config1", ":config2", ":config3"): [":standard_lib"],
        ":config4": [":special_lib"],
    }),
)

selects.config_setting_group

通过 config_setting_group Skylibselects 模块支持OR多个 config_setting

load("@bazel_skylib//lib:selects.bzl", "selects")
config_setting(
    name = "config1",
    values = {"cpu": "arm"},
)
config_setting(
    name = "config2",
    values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
    name = "config1_or_2",
    match_any = [":config1", ":config2"],
)
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1_or_2": [":standard_lib"],
        "//conditions:default": [":other_lib"],
    }),
)

selects.with_or不同,不同的目标可以在:config1_or_2 不同属性。

匹配多个条件时出错,除非有一个条件明确无误 “专精领域认证”或全部解析为相同的值。如需了解详情,请点击此处

AND 链

如果您需要在多个条件匹配时匹配 select 分支,请使用 Skylibconfig_setting_group:

config_setting(
    name = "config1",
    values = {"cpu": "arm"},
)
config_setting(
    name = "config2",
    values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
    name = "config1_and_2",
    match_all = [":config1", ":config2"],
)
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1_and_2": [":standard_lib"],
        "//conditions:default": [":other_lib"],
    }),
)

与 OR 链接不同,现有 config_setting 无法直接AND 位于 select 内。您必须将它们显式封装在 config_setting_group 中。

自定义错误消息

默认情况下,如果没有任何条件匹配,select() 会附加到的目标 失败并显示以下错误:

ERROR: Configurable attribute "deps" doesn't match this configuration (would
a default condition help?).
Conditions checked:
  //tools/cc_target_os:darwin
  //tools/cc_target_os:android

可使用 no_match_error 对此进行自定义。 属性:

cc_library(
    name = "my_lib",
    deps = select(
        {
            "//tools/cc_target_os:android": [":android_deps"],
            "//tools/cc_target_os:windows": [":windows_deps"],
        },
        no_match_error = "Please build with an Android or Windows toolchain",
    ),
)
$ bazel build //myapp:my_lib
ERROR: Configurable attribute "deps" doesn't match this configuration: Please
build with an Android or Windows toolchain

规则兼容性

规则实现会收到可配置的解析值 属性。例如,假设:

# myapp/BUILD

some_rule(
    name = "my_target",
    some_attr = select({
        ":foo_mode": [":foo"],
        ":bar_mode": [":bar"],
    }),
)
$ bazel build //myapp/my_target --define mode=foo

规则实现代码看到的 ctx.attr.some_attr[":foo"]

宏可以接受 select() 子句并将其传递给原生代码 规则。但它们无法直接操控它们。例如,没有方法 宏来转换

select({"foo": "val"}, ...)

select({"foo": "val_with_suffix"}, ...)

原因有两个。

首先,需要知道 select 将选择哪个路径的宏无法正常运行 因为宏是在 Bazel 的加载阶段进行评估的, 这发生在标志值已知之前 这是核心 Bazel 设计限制,短期内不太可能更改。

其次,只需要遍历所有 select 路径的宏,而 技术可行,缺乏连贯的界面。需要进一步设计才能更改 这个。

Bazel 查询和 cquery

Bazel query会针对 Bazel 的 加载阶段。 这意味着它不知道目标使用了什么命令行标记,因为这些标记 标志在 build 中之后才会进行求值(在 分析阶段)。 因此无法确定选择的是哪个 select() 分支。

Bazel cquery 在 Bazel 的分析阶段结束后运行,因此具有 所有这些信息,并且可以准确解析 select()

请考虑以下因素:

load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
# myapp/BUILD

string_flag(
    name = "dog_type",
    build_setting_default = "cat"
)

cc_library(
    name = "my_lib",
    deps = select({
        ":long": [":foo_dep"],
        ":short": [":bar_dep"],
    }),
)

config_setting(
    name = "long",
    flag_values = {":dog_type": "dachshund"},
)

config_setting(
    name = "short",
    flag_values = {":dog_type": "pug"},
)

query 粗略估算了 :my_lib 的依赖项:

$ bazel query 'deps(//myapp:my_lib)'
//myapp:my_lib
//myapp:foo_dep
//myapp:bar_dep

cquery 会显示其确切依赖项:

$ bazel cquery 'deps(//myapp:my_lib)' --//myapp:dog_type=pug
//myapp:my_lib
//myapp:bar_dep

常见问题解答

为什么 select() 在宏中不起作用?

select() 在规则中确实起作用!请参阅规则兼容性,了解 。

这个问题通常表示的一个关键问题是,select() 在 v2 中 。这些规则与规则不同。请参阅 关于规则的文档 以了解其中的区别。 下面是一个端到端示例:

定义规则和宏:

# myapp/defs.bzl

# Rule implementation: when an attribute is read, all select()s have already
# been resolved. So it looks like a plain old attribute just like any other.
def _impl(ctx):
    name = ctx.attr.name
    allcaps = ctx.attr.my_config_string.upper()  # This works fine on all values.
    print("My name is " + name + " with custom message: " + allcaps)

# Rule declaration:
my_custom_bazel_rule = rule(
    implementation = _impl,
    attrs = {"my_config_string": attr.string()},
)

# Macro declaration:
def my_custom_bazel_macro(name, my_config_string):
    allcaps = my_config_string.upper()  # This line won't work with select(s).
    print("My name is " + name + " with custom message: " + allcaps)

实例化规则和宏:

# myapp/BUILD

load("//myapp:defs.bzl", "my_custom_bazel_rule")
load("//myapp:defs.bzl", "my_custom_bazel_macro")

my_custom_bazel_rule(
    name = "happy_rule",
    my_config_string = select({
        "//third_party/bazel_platforms/cpu:x86_32": "first string",
        "//third_party/bazel_platforms/cpu:ppc": "second string",
    }),
)

my_custom_bazel_macro(
    name = "happy_macro",
    my_config_string = "fixed string",
)

my_custom_bazel_macro(
    name = "sad_macro",
    my_config_string = select({
        "//third_party/bazel_platforms/cpu:x86_32": "first string",
        "//third_party/bazel_platforms/cpu:ppc": "other string",
    }),
)

构建失败,因为 sad_macro 无法处理 select()

$ bazel build //myapp:all
ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
  (most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
  my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().
ERROR: error loading package 'myapp': Package 'myapp' contains errors.

当您注释掉 sad_macro 时,构建成功:

# Comment out sad_macro so it doesn't mess up the build.
$ bazel build //myapp:all
DEBUG: /myworkspace/myapp/defs.bzl:5:3: My name is happy_macro with custom message: FIXED STRING.
DEBUG: /myworkspace/myapp/hi.bzl:15:3: My name is happy_rule with custom message: FIRST STRING.

这种情况无法改变,因为根据定义,宏会先求值, Bazel 会读取构建的命令行标志。这意味着 对 select() 求值的信息。

不过,宏可以将 select() 作为不透明 blob 传递给规则:

# myapp/defs.bzl

def my_custom_bazel_macro(name, my_config_string):
    print("Invoking macro " + name)
    my_custom_bazel_rule(
        name = name + "_as_target",
        my_config_string = my_config_string,
    )
$ bazel build //myapp:sad_macro_less_sad
DEBUG: /myworkspace/myapp/defs.bzl:23:3: Invoking macro sad_macro_less_sad.
DEBUG: /myworkspace/myapp/defs.bzl:15:3: My name is sad_macro_less_sad with custom message: FIRST STRING.

为什么 select() 始终返回 true?

因为按照定义,(但并非规则) 无法评估 select(),任何尝试这样做的行为 通常会产生错误:

ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
  (most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
  my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().

布尔值是一种特殊情况,会在不发出提示的情况下失败,因此应特别注意 并保持警惕:

$ cat myapp/defs.bzl
def my_boolean_macro(boolval):
  print("TRUE" if boolval else "FALSE")

$ cat myapp/BUILD
load("//myapp:defs.bzl", "my_boolean_macro")
my_boolean_macro(
    boolval = select({
        "//third_party/bazel_platforms/cpu:x86_32": True,
        "//third_party/bazel_platforms/cpu:ppc": False,
    }),
)

$ bazel build //myapp:all --cpu=x86
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.
$ bazel build //mypro:all --cpu=ppc
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.

之所以发生这种情况,是因为宏无法理解 select() 的内容。 因此,它们真正评估的是 select() 对象本身。根据 Pythonic 设计 所有对象(除了极少数的异常值除外) 则会自动返回 true。

我可以像字典一样读取 select() 吗?

无法对选择进行求值,因为宏会先求值,然后再求值 Bazel 知道构建的命令行参数是什么。他们至少能读 select() 的字典,以便向每个值添加后缀,该怎么办?

从概念上讲,这是可行的,但还不是 Bazel 功能。 您现在做的是准备一本简单的字典,然后将其输入 select()

$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
  for key in select_cmd.keys():
    select_cmd[key] += " WITH SUFFIX"
  native.genrule(
      name = name,
      outs = [name + ".out"],
      srcs = [],
      cmd = "echo " + select(select_cmd + {"//conditions:default": "default"})
        + " > $@"
  )

$ cat myapp/BUILD
selecty_genrule(
    name = "selecty",
    select_cmd = {
        "//third_party/bazel_platforms/cpu:x86_32": "x86 mode",
    },
)

$ bazel build //testapp:selecty --cpu=x86 && cat bazel-genfiles/testapp/selecty.out
x86 mode WITH SUFFIX

如果您想同时支持 select() 和原生类型,可以执行以下操作:

$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
    cmd_suffix = ""
    if type(select_cmd) == "string":
        cmd_suffix = select_cmd + " WITH SUFFIX"
    elif type(select_cmd) == "dict":
        for key in select_cmd.keys():
            select_cmd[key] += " WITH SUFFIX"
        cmd_suffix = select(select_cmd + {"//conditions:default": "default"})

    native.genrule(
        name = name,
        outs = [name + ".out"],
        srcs = [],
        cmd = "echo " + cmd_suffix + "> $@",
    )

为什么 select() 无法与 bind() 配合使用?

首先,不要使用 bind(),它已废弃,取而代之的是 alias()

从技术角度而言,bind() 是一个代码库 而不是 build 规则

Repo 规则没有特定的配置,不会在 创建规则的方式与构建规则相同因此,bind() 中的 select() 不能 对任何特定分支进行求值。

而应使用alias()以及select() actual 属性,以执行此类运行时确定。这个 它能够正常运行,因为 alias() 是一条 BUILD 规则,并且是通过 特定配置。

如果需要,您甚至可以将 bind() 目标指向 alias()

$ cat WORKSPACE
workspace(name = "myapp")
bind(name = "openssl", actual = "//:ssl")
http_archive(name = "alternative", ...)
http_archive(name = "boringssl", ...)

$ cat BUILD
config_setting(
    name = "alt_ssl",
    define_values = {
        "ssl_library": "alternative",
    },
)

alias(
    name = "ssl",
    actual = select({
        "//:alt_ssl": "@alternative//:ssl",
        "//conditions:default": "@boringssl//:ssl",
    }),
)

使用此设置,您可以传递 --define ssl_library=alternative 以及任何目标 依赖于 //:ssl//external:ssl 的应用将看到备用方式 位于 @alternative//:ssl

但实际上,请停止使用 bind()

为什么我的 select() 没有选择预期结果?

如果 //myapp:fooselect() 未选择您期望的条件, 使用 cquerybazel config 进行调试:

如果 //myapp:foo 是您要构建的顶级目标,请运行以下命令:

$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)

如果您要构建依赖于您 API 的其他目标 //bar, //myapp:foo 中某个地方,运行以下命令:

$ bazel cquery 'somepath(//bar, //myapp:foo)' <desired build flags>
//bar:bar   (3ag3193fee94a2)
//bar:intermediate_dep (12e23b9a2b534a)
//myapp:foo (12e23b9a2b534a)

//myapp:foo 旁的 (12e23b9a2b534a)哈希 解析 //myapp:fooselect() 的配置。您可以检查 带有 bazel config 的值:

$ bazel config 12e23b9a2b534a
BuildConfigurationValue 12e23b9a2b534a
Fragment com.google.devtools.build.lib.analysis.config.CoreOptions {
  cpu: darwin
  compilation_mode: fastbuild
  ...
}
Fragment com.google.devtools.build.lib.rules.cpp.CppOptions {
  linkopt: [-Dfoo=bar]
  ...
}
...

然后将此输出与每个 config_setting 的预期设置进行比较。

//myapp:foo 可能存在于同一 build 中的不同配置中。请参阅 参阅 cquery 文档,了解如何使用 somepath 获取 一个。

为什么 select() 不能与平台配合使用?

Bazel 不支持可配置的属性,用于检查给定平台是否 是目标平台,因为语义不清晰。

例如:

platform(
    name = "x86_linux_platform",
    constraint_values = [
        "@platforms//cpu:x86",
        "@platforms//os:linux",
    ],
)

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":x86_linux_platform": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

在此 BUILD 文件中,如果目标平台同时具有select() @platforms//cpu:x86@platforms//os:linux 约束条件,但不是 此处定义了“:x86_linux_platform”?BUILD 文件的作者和用户 不同平台的创作者可能会有不同的想法。

我该怎么做?

而是定义一个与任何具有如下特征的平台匹配的 config_setting 这些限制:

config_setting(
    name = "is_x86_linux",
    constraint_values = [
        "@platforms//cpu:x86",
        "@platforms//os:linux",
    ],
)

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":is_x86_linux": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

此过程会定义特定的语义,让用户更清楚地了解 满足期望的条件。

如果我确实想在该平台上select,该怎么办?

如果您的构建要求特别要求检查平台, 可以翻转 config_setting--platforms 标志的值:

config_setting(
    name = "is_specific_x86_linux_platform",
    values = {
        "platforms": ["//package:x86_linux_platform"],
    },
)

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":is_specific_x86_linux_platform": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

Bazel 团队不认可这种做法;它会过度限制您的构建 当预期条件不匹配时,会让用户感到困惑。