可設定的屬性 (通常稱為 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
會變成:
指令 | 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 上執行時,這項作業不會造成混淆,因為兩個分支都會解析為「hello」。{"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"}
* 其中一個人的 values
嚴格來說是其他所有人的超集。舉例來說,values = {"cpu": "x86", "compilation_mode": "dbg"}
是 values = {"cpu": "x86"}
的明確特化版本。
如果沒有其他條件相符,系統就會自動比對內建條件 //conditions:default
。
雖然這個範例使用 deps
,但 select()
也適用於 srcs
、resources
、cmd
和大多數其他屬性。只有少數屬性無法設定,且這些屬性會清楚註記。舉例來說,config_setting
自己的 values
屬性無法設定。
select()
和依附元件
某些屬性會變更目標下所有遞移依附元件的建構參數。舉例來說,genrule
的 tools
會變更為執行 Bazel 的機器的 CPU (由於交叉編譯,這可能與目標建構的 CPU 不同)。--cpu
這就是所謂的「設定轉換」。
Given
#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
開發人員電腦上,將建構作業繫結至 g_arm.src
、tool1
和 x86tool.cc
。附加至 my_genrule
的兩個 select
都會使用 my_genrule
的建構參數,包括 --cpu=arm
。tools
屬性會將 --cpu
變更為 x86
,適用於 tool1
和遞移依附元件。tool1
上的 select
會使用 tool1
的建構參數,包括 --cpu=x86
。
設定條件
可設定屬性中的每個鍵都是 config_setting
或 constraint_value
的標籤參照。
config_setting
只是預期指令列旗標設定的集合。將這些條件封裝在目標中,使用者就能輕鬆維護「標準」條件,並從多個位置參照這些條件。
constraint_value
支援多平台行為。
內建旗標
Bazel 內建 --cpu
等旗標,建構工具可原生瞭解所有專案中的所有建構項目。這些屬性會透過 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 建構設定,為專案專屬的標記建立模型。與內建標記不同,這些標記定義為建構目標,因此 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 建構設定。
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()
's
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
ing 條件:
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
路徑,雖然技術上可行,但缺乏一致的 UI。如要變更這項設定,必須進一步設計。
Bazel 查詢和 cquery
Bazel query
會在 Bazel 的載入階段運作。也就是說,由於這些旗標要到建構作業的稍後階段 (分析階段) 才會評估,因此 Bazel 無法得知目標使用的指令列旗標。因此無法判斷要選擇哪些 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() does work in rules! 詳情請參閱「規則相容性」一文。
這個問題通常表示 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 讀取建構指令列旗標之前評估。也就是說,資訊不足,無法評估 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 知道建構的指令列參數之前評估。他們至少可以讀取 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()
。這項功能已遭淘汰,請改用 alias()
。
從技術角度來看,bind()
是 repo 規則,不是 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
中的替代項目。
但真的,請停止使用 bind()
。
為什麼 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
可能會出現在同一建構版本的不同設定中。如要瞭解如何使用 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": [],
}),
)
如果目標平台同時具有 @platforms//cpu:x86
和 @platforms//os:linux
限制,但不是這裡定義的 :x86_linux_platform
,則應使用哪個 select()
?BUILD
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 團隊不建議這麼做,因為這會過度限制建構作業,且在預期條件不符時,會讓使用者感到困惑。