可設定的建構屬性

回報問題 查看原始碼 夜間 7.4 ,直接在 Google Cloud 控制台實際操作。 7.3 7.2 7.1 7.0 6.5

可設定屬性 (通常稱為 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追蹤 Deployment 指令列具體來說,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 上執行時,這會是明確的 {"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"},因為兩個分支都會解析為「hello」。* 一個 values 是所有其他 values 的嚴格超集。例如:values = {"cpu": "x86", "compilation_mode": "dbg"}values = {"cpu": "x86"} 的明確專業認證。

系統會在下列情況自動比對內建條件 //conditions:default 不會產生其他影響

雖然這個範例使用 deps,但 select() 同樣適用於 srcsresourcescmd 和大多數其他屬性。只有少數屬性是不可設定的,且這些屬性會清楚標註。舉例來說,config_setting 本身的 values 屬性無法設定。

select() 和依附元件

某些屬性會變更目標下所有傳遞依附元件的建構參數。舉例來說,genruletools 會將 --cpu 變更為 執行 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

x86 開發人員機器上的版本會將建構繫結至 g_arm.srctool1x86tool.cc。附加至 my_genrule 的兩個 select 都會使用 my_genrule 的建構參數,包括 --cpu=armtools 屬性會將 --cpu 變更為 x86,適用於 tool1 及其遞移依附元件。tool1 上的 select 會使用 tool1 的建構參數,包括 --cpu=x86

設定條件

可設定屬性中的每個鍵都是 config_settingconstraint_value 的標籤參照。

config_setting 只是預期的指令列旗標設定集合。只要將這些內容封裝到目標中 如何維持「標準」可從多個位置參照的條件

constraint_value 支援多平台行為

內建旗標

--cpu 等旗標已內建於 Bazel 中:建構工具會原生瞭解所有專案的所有建構作業。指定為 config_settingvalues 屬性:

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_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 版本設定。

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",
    ],
)

您可以透過指令列指定平台。它會啟動 config_setting,其中包含平台的 constraint_values、 讓這些 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

除非其中一個條件是其他條件的明確「專門化」(specialization),或是所有條件都解析為相同的值,否則多個條件無法相符。詳情請參閱這篇文章

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 無法直接在 selectAND。您必須明確將這些元素包裝在 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。必須進一步設計才能變更 而負責任的 AI 技術做法 有助於達成這項目標

Bazel 查詢和 cquery

Bazel query 會在 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()「可」在規則中使用!請參閱「規則相容性」一文,瞭解 詳細資料。

這個問題的主要問題通常是因為 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()s 的資料。

不過,巨集可以將 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() 物件本身。根據 Python 設計 除了極少數例外狀況之外的所有物件 會自動傳回 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 = {
        "//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:fooselect() 未選擇您預期的條件, 使用 cquerybazel 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)

(12e23b9a2b534a) 旁邊的 //myapp:foo雜湊 設定該設定會解析 //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 可能會出現在同一個版本的不同設定中。如要瞭解如何使用 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 檔案中,如果目標平台同時擁有select() @platforms//cpu:x86@platforms//os:linux 限制條件,但「不是」 這裡已定義 :x86_linux_platformBUILD 檔案的作者和使用者 每個平台定義了獨立平台 可能會有不同的想法

請問我該怎麼做?

請改為定義 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 團隊不會為此背書。會對建構造成太大影響 使用者會因預期狀況不符,而感到混淆。