可配置的属性(通常称为 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
上也可以发挥同样的效果。
resources
、cmd
和大多数其他属性。只有少量属性
是不可配置的,并带有明确注释。例如:
config_setting
自己的
values
属性不可配置。
select()
和依赖项
某些属性会更改所有传递依赖项的 build 参数
。例如,genrule
的 tools
将 --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.src
、tool1
和x86
x86tool.cc
。附加到 my_genrule
的两个 select
都使用 my_genrule
的
build 参数,其中包含 --cpu=arm
。tools
属性会发生变化
对于 tool1
及其传递依赖项,将 --cpu
设置为 x86
。select
tool1
使用 tool1
的构建参数,其中包括 --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
是该标记的预期值。如果满足以下条件,则 :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_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
通过
with_or
Skylib 中
selects
模块直接支持在 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
Skylib 中
selects
模块支持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
无法直接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 规则,并且是通过
特定配置。
$ 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:foo
的 select()
未选择您期望的条件,
使用 cquery 和 bazel 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: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 中的不同配置中。请参阅
参阅 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 团队不认可这种做法;它会过度限制您的构建 当预期条件不匹配时,会让用户感到困惑。