設定

回報問題 查看來源 夜間 7.2 7.1 7.0 6.5 6.4

本頁說明 Starlark 設定的優點和基本用法。 Bazel 的 API,用來自訂專案建構方式。其中包括 建構設定並提供範例

這麼做可以:

  • 定義專案的自訂標記 --define
  • 寫入 轉換來設定依附元件 有別於家長 (例如 --compilation_mode=opt--cpu=arm)
  • 將更好的預設值烘焙成規則 (例如自動建構 //my:android_app 指定的 SDK 上執行)

並全部移除 .bzl 檔案 (無需使用 Bazel 版本)。詳情請參閱 bazelbuild/examples 存放區: 範例

使用者定義的建構設定

建構設定是 設定 可能不準確或不適當請將設定視為鍵/值對應。正在設定--cpu=ppc --copt="-DFoo" 會產生如下圖所示的設定 {cpu: ppc, copt: "-DFoo"}。每個項目都是建構設定。

cpucopt 等傳統旗標為原生設定: 其鍵會定義,且其值會在原生 bazel Java 程式碼中設定。 Bazel 使用者只能透過指令列讀取及寫入 以及其他原生維護的 API變更原生旗標和 API 必須發布階段式推出才能公開發布的產品使用者定義的建構作業 設定是在 .bzl 檔案中定義,因此,您不需要 Terraform 版本, 註冊變更)。您也可以透過指令列進行設定 (如果它們是flags,請參見下文),但您也可以 透過使用者定義的轉場效果進行設定。

定義建構設定

端對端範例

build_setting rule() 參數

版本設定是與任何其他規則一樣的規則,可以使用 Starlark rule() 函式的 build_setting 屬性。

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

build_setting 屬性會採用一個函式,用來指定 建構設定這種型別只適用於一組基本的 Starlark 類型,例如 《bool》和《string》。請參閱 config 模組 說明文件。輸入內容較為複雜 所做變更詳情請參閱下方說明。

config 模組的函式會採用選用的布林參數 flag、 預設值為 false。如果 flag 設為 True,建構設定 使用者和內部人員都能在指令列上設定 預設值和轉換。 使用者不一定能調整所有設定。舉例來說 編寫者,您想在測試規則中開啟一些偵錯模式 您不想讓使用者自行開啟 納入其他非測試規則中的特徵

使用 ctx.build_setting_value

如同所有規則,建構設定規則具有實作函式。 建構設定的基本 Starlark 類型值可透過 ctx.build_setting_value 方法。這個方法僅適用於 ctx 物件。這些實作方式 方法可直接轉送建構設定值,或執行其他工作 例如型別檢查或更複雜的結構體建立作業方法如下 實作 enum 類型的建構設定:

# example/buildsettings/build_settings.bzl
TemperatureProvider = provider(fields = ['type'])

temperatures = ["HOT", "LUKEWARM", "ICED"]

def _impl(ctx):
    raw_temperature = ctx.build_setting_value
    if raw_temperature not in temperatures:
        fail(str(ctx.label) + " build setting allowed to take values {"
             + ", ".join(temperatures) + "} but was set to unallowed value "
             + raw_temperature)
    return TemperatureProvider(type = raw_temperature)

temperature = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

定義多設定字串旗標

字串設定有額外的 allow_multiple 參數,可讓 旗標,在指令列或 bazelrcs 中多次設定此標記。預設設定 值仍由字串類型屬性設定:

# example/buildsettings/build_settings.bzl
allow_multiple_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "allow_multiple_flag")
allow_multiple_flag(
    name = "roasts",
    build_setting_default = "medium"
)

系統會將標記的各項設定視為單一值:

$ bazel build //my/target --//example:roasts=blonde \
    --//example:roasts=medium,dark

上述內容已剖析為 {"//example:roasts": ["blonde", "medium,dark"]}ctx.build_setting_value 會傳回 ["blonde", "medium,dark"] 清單。

將建構設定執行個體化

使用 build_setting 參數定義的規則具有隱含的強制性 build_setting_default 屬性。這項屬性與 由 build_setting 參數宣告。

# example/buildsettings/build_settings.bzl
FlavorProvider = provider(fields = ['type'])

def _impl(ctx):
    return FlavorProvider(type = ctx.build_setting_value)

flavor = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)

預先定義的設定

端對端範例

Skylib 程式庫包含一組預先定義的設定,您可以執行個體化,不必這麼做 編寫自訂的 Starlark

舉例來說,如要定義接受一組有限字串值的設定:

# example/BUILD
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
    name = "myflag",
    values = ["a", "b", "c"],
    build_setting_default = "a",
)

如需完整清單,請參閱: 常見建構設定規則

使用建構設定

視建構設定而定

如果目標想要讀取設定資訊 透過一般屬性依附元件,直接依附建構設定。

# example/rules.bzl
load("//example/buildsettings:build_settings.bzl", "FlavorProvider")
def _rule_impl(ctx):
    if ctx.attr.flavor[FlavorProvider].type == "ORANGE":
        ...

drink_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "flavor": attr.label()
    }
)
# example/BUILD
load("//example:rules.bzl", "drink_rule")
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)
drink_rule(
    name = "my_drink",
    flavor = ":favorite_flavor",
)

語言可能會建立一組標準建構設定,所有規則皆適用 取決於語言種類雖然 fragments 的原生概念已不敷使用 是以硬式編碼物件的形式存在於 Starlark 設定世界中 這項概念建議使用一組共同的隱含屬性。例如:

# kotlin/rules.bzl
_KOTLIN_CONFIG = {
    "_compiler": attr.label(default = "//kotlin/config:compiler-flag"),
    "_mode": attr.label(default = "//kotlin/config:mode-flag"),
    ...
}

...

kotlin_library = rule(
    implementation = _rule_impl,
    attrs = dicts.add({
        "library-attr": attr.string()
    }, _KOTLIN_CONFIG)
)

kotlin_binary = rule(
    implementation = _binary_impl,
    attrs = dicts.add({
        "binary-attr": attr.label()
    }, _KOTLIN_CONFIG)

在指令列中使用建構設定

與大多數原生旗標類似,您可以使用指令列調整建構設定 標記為標示建構作業 設定的名稱是其完整目標路徑,使用 name=value 語法:

$ bazel build //my/target --//example:string_flag=some-value # allowed
$ bazel build //my/target --//example:string_flag some-value # not allowed

支援特殊布林值語法:

$ bazel build //my/target --//example:boolean_flag
$ bazel build //my/target --no//example:boolean_flag

使用建構設定別名

您可以為建構設定目標路徑設定別名,使其更容易讀取 建立虛擬機器別名的功能與原生旗標類似,也可以使用 第一個輸入值

新增「--flag_alias=ALIAS_NAME=TARGET_PATH」以設定別名 至您的 .bazelrc。舉例來說,如要將別名設為 coffee,請按照下列步驟操作:

# .bazelrc
build --flag_alias=coffee=//experimental/user/starlark_configurations/basic_build_setting:coffee-temp

最佳做法:多次設定別名會導致最新的 優先順序原則使用不重複的別名名稱,避免意外剖析結果。

如要使用別名,請輸入別名,取代建構設定目標路徑。 根據上述 coffee 範例,已在使用者的 .bazelrc 中設定:

$ bazel build //my/target --coffee=ICED

而不是

$ bazel build //my/target --//experimental/user/starlark_configurations/basic_build_setting:coffee-temp=ICED

最佳做法:雖然您可以在指令列中設定別名, 在 .bazelrc 中可減少指令列的雜訊。

標籤類型的建構設定

端對端範例

與其他建構設定不同,您無法以 build_setting 規則參數。但 bazel 有兩個內建規則: 《label_flag》和《label_setting》。這些規則會轉送至 實際目標。「label_flag」和 系統可透過轉場效果讀取/寫入 label_setting,且可設定 label_flag 如同其他 build_setting 規則一樣唯一的差別在於 也無法自訂

「標籤」類型的設定最終會取代遲交的功能 預設值。延遲繫結的預設屬性為標籤類型屬性, 最終值可能會受到設定影響在 Starlark 中,這將會取代 configuration_field 也能使用 Google Cloud CLI 或 Compute Engine API

# example/rules.bzl
MyProvider = provider(fields = ["my_field"])

def _dep_impl(ctx):
    return MyProvider(my_field = "yeehaw")

dep_rule = rule(
    implementation = _dep_impl
)

def _parent_impl(ctx):
    if ctx.attr.my_field_provider[MyProvider].my_field == "cowabunga":
        ...

parent_rule = rule(
    implementation = _parent_impl,
    attrs = { "my_field_provider": attr.label() }
)

# example/BUILD
load("//example:rules.bzl", "dep_rule", "parent_rule")

dep_rule(name = "dep")

parent_rule(name = "parent", my_field_provider = ":my_field_provider")

label_flag(
    name = "my_field_provider",
    build_setting_default = ":dep"
)

建構設定和 select()

端對端範例

使用者可以透過 select()。建構設定目標可以傳遞至flag_values config_setting。系統會將與設定比對的值以 String 之後會剖析為建構設定的類型,以便進行比對。

config_setting(
    name = "my_config",
    flag_values = {
        "//example:favorite_flavor": "MANGO"
    }
)

使用者定義的轉場效果

設定 轉換 會將已設定的目標對應至 建構圖表

定義

轉換會定義規則之間的設定變更。例如要求 例如「針對與父項不同的 CPU 編譯依附元件」都會由 轉換。

正式上,轉換是指從輸入設定到一或多個函式 輸出設定多數轉場效果會是 1:1,例如「覆寫輸入內容」 「--cpu=ppc」設定。也有適合 1:2 以上的轉場效果 有特殊限制

在 Starlark 中,轉場效果的定義與規則類似, transition() 函式 以及實作函式

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//example:favorite_flavor" : "MINT"}

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

transition() 函式採用實作函式, 用於讀取的建構設定(inputs),以及一組要寫入的建構設定 (outputs).實作函式有兩個參數:settingsattr。「settings」是已宣告所有設定的字典 {String:Object} 在 transition()inputs 參數中。

attr 是屬性和值的字典, 請參閱如果以 傳出邊緣轉換,則 屬性都是已設定的 post-select() 解析度。以下列身分附加時: 即將展開的邊緣轉換attr 不會 加入所有使用選取器解析值的屬性。如果 --foo 的連入邊緣轉場會讀取屬性 bar,然後 在 --foo 上選取屬性 bar 設定屬性後 傳入邊緣轉換在轉場時讀取錯誤的 bar 值。

實作函式必須傳回字典 (或稱 舉例來說 具有多個輸出設定的轉場效果) 您將套用新建構設定值傳回的字典金鑰組 包含傳遞至 outputs 的一組建構設定 參數的值。即使建構設定 在轉換期間不會實際變動,因此原始值必須 明確傳遞給傳回的字典中。

定義 1:2 以上的轉場效果

端對端範例

傳出邊緣轉換可以對應單一輸入 並設定兩項以上的輸出設定這有助於定義 多層架構程式碼的規則

1:2 以上的轉場效果,是透過傳回 轉換實作函式。

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return [
        {"//example:favorite_flavor" : "LATTE"},
        {"//example:favorite_flavor" : "MOCHA"},
    ]

coffee_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

他們也可以設定自訂鍵,讓規則導入功能用於 讀取個別依附元件:

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

附加轉場效果

端對端範例

轉場效果可連接以下兩處:外來邊緣和向外邊緣。 實際上,這表示規則可自行轉換設定 ( 並轉換其依附元件設定 (傳出 邊緣轉場)。

注意:目前無法將 Starlark 轉換附加至原生規則。 如需執行這項操作,請與 bazel-discuss@googlegroups.com ,瞭解如何找出解決方法。

連入邊緣轉場效果

附加 transition 物件,即可啟用傳入邊緣轉換功能 (由 transition() 建立) 變更為 rule()cfg 參數:

# example/rules.bzl
load("example/transitions:transitions.bzl", "hot_chocolate_transition")
drink_rule = rule(
    implementation = _impl,
    cfg = hot_chocolate_transition,
    ...

連入邊緣轉場必須為 1:1 轉場效果。

傳出邊緣轉場效果

附加 transition 物件即可啟用傳出邊緣轉場效果 (由 transition() 建立) 附加至屬性的 cfg 參數:

# example/rules.bzl
load("example/transitions:transitions.bzl", "coffee_transition")
drink_rule = rule(
    implementation = _impl,
    attrs = { "dep": attr.label(cfg = coffee_transition)}
    ...

連出邊緣轉場可為 1:1 或 1:2 以上。

請參閱「使用轉場效果存取屬性」一節 瞭解如何讀取這些金鑰

原生選項轉換

端對端範例

Starlark 轉場效果也可以在原生建構上宣告讀取與寫入 對選項名稱加上特殊的前置字串

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//command_line_option:cpu": "k8"}

cpu_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]

不支援的原生選項

Bazel 不支援在 --define 上進行轉換, "//command_line_option:define"。而是改用 建構設定。一般來說,新的 不建議使用 --define 取代建構設定。

Bazel 不支援在 --config 上轉換。這是因為 --config 是 「擴展」的旗標。

至關重要的一點是,--config 可能含有不會影響建構設定的標記。 例如 --spawn_strategy ,直接在 Google Cloud 控制台實際操作。Bazel 在設計上無法將這類標記繫結至個別目標。也就是說 沒有時效性的方式是在轉場效果中套用

如要解決這個問題,您可以明確列出「屬於」的標記 轉換的設定這需要維持 --config 的 同時展開兩個地方,這是已知的 UI 模糊效果。

啟用多個建構設定的轉換

設置建構設定時 允許多個值,則 您必須透過清單來進行設定

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "string_flag")
string_flag(name = "roasts", build_setting_default = "medium")
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    # Using a value of just "dark" here will throw an error
    return {"//example:roasts" : ["dark"]},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:roasts"]
)

免人工管理轉場效果

如果轉場效果傳回 {}[]None,這是保留所有儲存格的簡寫 維持原始設定值比起明確提示 讓每個輸出內容

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (attr)
    if settings["//example:already_chosen"] is True:
      return {}
    return {
      "//example:favorite_flavor": "dark chocolate",
      "//example:include_marshmallows": "yes",
      "//example:desired_temperature": "38C",
    }

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = ["//example:already_chosen"],
    outputs = [
        "//example:favorite_flavor",
        "//example:include_marshmallows",
        "//example:desired_temperature",
    ]
)

透過轉換存取屬性

端對端範例

將轉場效果附加至連出邊緣時 (無論轉場效果是 1:1 或 1:2 以上的轉場效果),ctx.attr 都會強製成為清單 如果尚未加入容器系統未指定這份清單中的元素順序。

# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    return {"//example:favorite_flavor" : "LATTE"},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

def _rule_impl(ctx):
    # Note: List access even though "dep" is not declared as list
    transitioned_dep = ctx.attr.dep[0]

    # Note: Access doesn't change, other_deps was already a list
    for other_dep in ctx.attr.other_deps:
      # ...


coffee_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = coffee_transition)
        "other_deps": attr.label_list(cfg = coffee_transition)
    })

如果轉場效果為 1:2+ 並設定了自訂鍵,則可使用 ctx.split_attr 讀取每個鍵的個別依附元件:

# example/transitions/rules.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

def _rule_impl(ctx):
    apple_dep = ctx.split_attr.dep["Apple deps"]
    linux_dep = ctx.split_attr.dep["Linux deps"]
    # ctx.attr has a list of all deps for all keys. Order is not guaranteed.
    all_deps = ctx.attr.dep

multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = multi_arch_transition)
    })

查看完整範例 此處。

與平台和工具鍊整合

現今許多原生旗標 (例如 --cpu--crosstool_top) 與 工具鍊解析我們日後會針對這些類型的 很可能會取代 目標平台

記憶體和效能注意事項

在建構作業中新增轉換,以及新增設定後 成本:建構圖形加大、建構圖表較不易理解 建構應用程式當您考慮這些成本時 在您的建構規則中使用轉場效果以下是轉換流程範例 可能會使建構圖呈指數成長

行為不良的建構版本:個案研究

擴充性圖表

圖 1. 顯示頂層目標及其依附元件的擴充性圖表。

這張圖表顯示頂層目標 //pkg:app,取決於兩個目標 (即 //pkg:1_0//pkg:1_1。這兩個目標都取決於兩個目標://pkg:2_0//pkg:2_1。這兩種目標都取決於 //pkg:3_0//pkg:3_1 兩個目標。 這會持續到 //pkg:n_0//pkg:n_1,兩者都依賴單一 目標://pkg:dep

建立//pkg:app需要 \(2n+2\) 目標:

  • //pkg:app
  • //pkg:dep
  • //pkg:i_0//pkg:i_1 ( \(i\) - \([1..n]\))

假設您實作標記 須遵守《--//foo:owner=<STRING>》和《//pkg:i_b

depConfig = myConfig + depConfig.owner="$(myConfig.owner)$(b)"

也就是說,//pkg:i_b 會在 --owner 的舊值後面加上 b 解碼器

會產生下列設定的目標

//pkg:app                              //foo:owner=""
//pkg:1_0                              //foo:owner=""
//pkg:1_1                              //foo:owner=""
//pkg:2_0 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_0 (via //pkg:1_1)              //foo:owner="1"
//pkg:2_1 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_1 (via //pkg:1_1)              //foo:owner="1"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_0)  //foo:owner="00"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_1)  //foo:owner="01"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_0)  //foo:owner="10"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_1)  //foo:owner="11"
...

//pkg:dep」產生 \(2^n\) 設定的目標:config.owner= 「\(b_0b_1...b_n\)」使用 \(b_i\) \(\{0,1\}\)。

這會使建構圖比目標圖表指數大上許多, 對應的記憶體和效能結果

待辦事項:新增評估和緩解這些問題的策略。

延伸閱讀

如要進一步瞭解如何修改建構設定,請參閱: