可配置的属性(通常称为 select())是一项 Bazel 功能,可让用户在命令行中切换 build 规则属性的值。
例如,这可用于自动为架构选择合适实现的多平台库,或可在构建时自定义的功能可配置二进制文件。
示例
# 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,该 cc_binary 根据命令行中的标志“选择”其依赖项。具体而言,deps 会变为:
| 命令 | 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(),该属性在不同条件成立时会采用不同的值。
匹配必须明确:必须只有一个条件匹配;或者,如果多个条件匹配,则其中一个条件的 values 必须是所有其他条件的严格超集。例如,values = {"cpu": "x86", "compilation_mode": "dbg"} 是 values = {"cpu": "x86"} 的明确特例。内置条件 //conditions:default 在没有其他条件匹配时会自动匹配。
虽然此示例使用了 deps,但 select() 在 srcs、resources、cmd 和大多数其他属性上同样适用。只有少数属性是不可配置的,并且这些属性会明确注释。例如,config_setting 自身的 values 属性是不可配置的。
select() 和依赖项
某些属性会更改目标下所有传递依赖项的 build 参数。例如,genrule 的 tools 会将运行 Bazel 的机器的 CPU 更改为 --cpu(由于交叉编译,这可能与目标 build 所用的 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
在 x86 开发者机器上运行会将 build 绑定到 g_arm.src、tool1 和 x86tool.cc。附加到 my_genrule 的两个 select 都使用 my_genrule 的 build 参数,其中包括 --cpu=arm。tools 属性会将 tool1 及其传递依赖项的 --cpu 更改为 x86。tool1 上的 select 使用 tool1 的 build 参数,其中包括 --cpu=x86。
配置条件
可配置属性中的每个键都是对 config_setting 或 constraint_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 是相应标志的预期值。如果 values 中的每个条目都匹配,则 :meaningful_condition_name 匹配。顺序无关紧要。
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 设置来为自己的项目特定标志建模。与内置标志不同,这些标志被定义为 build 目标,因此 Bazel 会使用目标标签引用它们。
这些事件通过 config_setting 的 flag_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 设置。
values、flag_values 和 define_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_setting 在 select() 表达式中匹配。
例如,如需将 my_rocks 的 srcs 属性设置为 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
Skylib 的 selects 模块中的 with_or 宏支持直接在 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
Skylib 的 selects 模块中的 config_setting_group 宏支持 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 分支在多个条件匹配时匹配,请使用 Skylib 宏 config_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 无法直接在 select 内进行 AND。您必须明确将它们封装在 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 query 和 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() 在宏中不起作用。这些与规则不同。如需了解它们的区别,请参阅有关规则和宏的文档。 以下是一个端到端示例:
定义规则和宏:
# 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({
"//tools/target_cpu:x86": "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({
"//tools/target_cpu:x86": "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 读取 build 的命令行标志之前进行评估的。这意味着没有足够的信息来评估 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({
"//tools/target_cpu:x86": 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() 吗?
宏无法评估 select(s),因为宏在 Bazel 知道 build 的命令行参数是什么之前进行评估。他们是否至少可以读取 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 = {
"//tools/target_cpu:x86": "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() 是 WORKSPACE 规则,而不是 BUILD 规则。
工作区规则没有特定的配置,并且不会以与 BUILD 规则相同的方式进行评估。因此,bind() 中的 select() 实际上无法评估为任何特定分支。
您应使用 alias(),并在 actual 属性中使用 select() 来执行此类运行时确定。这可以正常运行,因为 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 的替代项。
为什么我的 select() 没有选择我预期的内容?
如果 //myapp:foo 具有未选择预期条件的 select(),请使用 cquery 和 bazel config 进行调试:
如果 //myapp:foo 是您要构建的顶级目标,请运行:
$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)
如果您要构建某个其他目标 //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:foo 的 select() 的配置的哈希。您可以使用 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 中的不同配置中。如需了解如何使用 somepath 获取正确的依赖项,请参阅 cquery 文档。
为什么 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 文件中,如果目标平台同时具有 @platforms//cpu:x86 和 @platforms//os:linux 约束条件,但不是此处定义的 :x86_linux_platform,应使用哪个 select()?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,该怎么办?
如果您的 build 要求明确需要检查平台,您可以在 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 团队不建议这样做;它会过度限制您的 build,并且在预期条件不匹配时让用户感到困惑。