Bazel 建構設定

建構設定是一組設定 (例如 cpu = "arm64"),其中每項設定都會將「設定值」指派給 Bazel 已知的已知設定變數。這些值會影響 Bazel 建構項目的方式。

建構設定可視為「不可變字典」將變數名稱 (字串鍵) 對應至設定值 (布林值、整數、字串、字串清單、標籤或標籤清單)。

只有在 Bazel 分析階段中,這些屬性才有意義,且會透過內容的唯一雜湊在內部識別。這類執行個體沒有標籤,並且不能直接顯示在 Bazel 建構檔案或 Starlark 程式碼中。

每個建構設定執行個體在 Bazel output_base 下都有自己的輸出目錄,即

${output_base}/execroot/<workspace_name>/bazel-out/<config_dir>/bin/

在建構設定情境中評估的目標建構構件會儲存在這裡。<config_dir> 值取決於建構設定的內容。這屬於 Bazel 實作細節,其在 Bazel 版本間可能有所不同。

在最簡單的情況下,<config_dir> 看起來會是 ${cpu}-${compilation_mode} (例如 k8-fastbuild1aarch64-dbg),但可能會變得較為複雜。

以下為一些小型 Bazel 專案範例的建構設定範例 config_dir 值:

  • k8-fastbuild
  • k8-fastbuild-ST-6f89e1bee3ea
  • k8-fastbuild-ST-bd2abcc18995
  • k8-fastbuild-ST-ec22d3eeb595
  • k8-opt
  • k8-opt-exec-2B5CBBC6
  • k8-opt-exec-2B5CBBC6-ST-5934bb4653e4

請注意,上述的十六進位值與設定 ID (即不重複的雜湊值) 相關。

常見的建構設定

根據預設,Bazel 會管理兩項設定:

  • 預設設定 又稱為「目標設定」,因為其對應於必須在最終「目標」系統上執行的建構構件。

    根據預設,這個檔案的設定與主機系統相符,但可以透過指令列選項變更內容 (請見下方說明)。

  • 主機設定與必須於執行 Bazel 的機器上執行的程式碼相對應。其中包含的設定與預設設定相同,但跨平台編譯時 (例如使用 --cpu=<name>) 除外。

此外,還有以下功能:

  • 執行設定,對應於建構動作期間執行的程式碼。實務上,這包含與主機版本相同的設定,但使用遠端建構工具時除外。

Bazel 專案也可以依據特定用途定義「額外設定」,例如在單一建構叫用中針對多個目標架構進行交叉編譯。

原生設定變數

bazel build 指令支援多種指令列選項,可變更原生設定變數 (又稱為 native 設定),例如:

  • --cpu=<name>--host_cpu=<name>

    分別變更為預設或主機設定產生的程式碼 CPU 架構。例如:

    bazel build --cpu=arm64 --host_cpu=x86_64 ...
    
  • -c <mode>--compilation_mode=<mode>--host_compilation_mode=<mode>

    其中 <mode> 是「fastbuild」、「dbg」或「opt」,用於描述一組編譯器連接器標記。例如:

    bazel build -c opt --host_compilation_mode=dbg ...
    
  • --crosstool=<file_path>--host_crosstool=<file_path>

    指向用於將自訂 C++ 工具鍊描述至 Bazel 的 CROSSTOOL 檔案,以便編譯及連結目標或主機二進位檔。

非常多的原生設定變數 (及相關指令列標記)。例如,Bazel 5.2.0 支援超過 340 種 (包括 83 種實驗性選項)。

自訂設定旗標 (已淘汰)

您可以定義自訂設定變數 (在 Bazel 說明文件中混用自訂設定旗標),該變數會在指令列上設為「--define <name>=<value>」,其中 <name> 是任意建構設定變數名稱,而 <value> 會記錄為任意字串 (系統一律不會解讀該值)。

您可以使用特殊結構在 BUILD.bazel 檔案中測試這些名稱,例如:

# This represents a named configuration condition which will be True whenever
# `--define foo=bar` is used in the `bazel build` command-line.
config_setting(
  name = "is_foo_bar",
  define_flags = {
    "foo": "bar",
  }
)

使用者定義的版本設定

為了克服自訂 --define 旗標的限制,Bazel 專案現在可以定義建構設定變數,以便:

  • 使用標籤命名 (提供工作區和套件範圍設定,以及可用性檢查)。

  • 可以有特定類型,可以是布林值、整數、字串、字串清單、標籤和標籤清單。

  • 請一律提供預設值。

只要在指令列中使用「--<label>=<value>」即可設定這些項目,如下所示:

# Set the build setting named enable_logs defined in
# $WORKSPACE/my_settings/BUILD.bazel to True.
#
# Note that the double-slash must follow the double caret directly
# without spaces between them.
bazel build --//my_settings:enable_logs=True …

這符合必須在 $PROJECT/my_settings/BUILD.bazel 檔案中顯示的定義,例如:

# From my_settings/BUILD.bazel
load("@bazel_skylib//rules/common_settings.bzl", "bool_flag")

bool_flag(
  name = "enable_logs",
  default_value = False
)

您也可以在外部存放區中定義建構設定,如下所示:

# Set the build setting named enable_logs defined in the config/BUILD.bazel
# file of the @project_settings external repository.
bazel build --@project_settings//config:enable_logs=True …

儲存使用者設定值

設定設定值的引數可以儲存在專案工作區目錄頂端的 .bazelrc 檔案中,而不需直接透過指令列傳遞,如下所示:

# from $PROJECT/.bazelrc
build --host_copt=-O3 -s
build --copt=-O1 -g -Wall
build --//my_settings:enable_logs=True

呼叫 bazel build <target> 時,系統會自動加入 .bazelrc 提供的選項,產生的指令相當於:

bazel build --host_copy="-O3 -s" --copt="-O1 -g -Wall" --//my_settings:enable_logs=True <target>

您也可以使用自訂 name 將數個定義分組,如下所示:

# from $PROJECT/.bazelrc
build:conf_x64 --cpu=x86_64
build:conf_x64 --copt=-mavx2

build:conf_arm64 --cpu=aarch64
build:conf_arm64 --copt=-marmv8.1-a+simd

然後使用 --config=<name> 從一個群組中選取所有選項,如下所示:

bazel build --config=conf_x64 <target>

等同於:

bazel build --cpu=x86_64 --copt=-mavx2 <target>

此外,您也可以將 --config 與其他選項合併,如以下所示:

bazel build --config=conf_arm64 --copy="-DENABLE_ASSERTS=1" ...

===

重要事項:儘管其名稱,--config 選項不會建立新的建構設定。這可讓您輕鬆為使用者將指令列選項分組。每個 <name> 都會以遞迴方式展開

正式成為標準字詞,那麼 Bazel 就完全忽略了這些內容。

設定轉換 (快速總覽)

除了標準目標、主機和執行設定之外,Bazel 也支援使用「轉換」的概念建立額外的建構設定。

轉場是進階功能,這裡不會詳述,但您必須瞭解以下幾點:

  • 從概念上來說,建構設定只是將設定變數名稱對應至設定值的字典。E.g.:

    {
       "copt": "-O2 -g",
       "cpu": "x86_64",
       "compiler": "gcc",
       "//my_settings:enable_logs": True,
       …
    }
    
  • 轉換作業提供的函式會採用目前的建構設定做為輸入內容,並傳回新的建構設定做為輸出內容。

  • 轉換函式只能修改字典中的值,也就是無法新增或移除輸入內容中的鍵。

  • 系統會在分析階段 (稍後說明) 特定條件下呼叫轉換函式,且使用者無法透過指令列或 .bazelrc 檔案直接觸發轉換函式。

檢查建構設定

透過 Bazel 建構指令,就能查看所需的所有設定。使用 bazel config 指令輸出所有設定的清單及其 config_dir 值,例如:

$ bazel clean
$ bazel build //src:program
$ bazel config
Available configurations:
20222e2616387f00ae3814d79f82a650829d1aea962d558edda5cf54c459f4a2 k8-fastbuild
30f5a27e1bd054836d97b800bdfe61c6d1cffccdf6b82c9963e94020e3852026 k8-fastbuild-ST-bd2abcc18995
34e198ac81dafe34b82cf62466cc84f5b1af6ef8dce44b9283b3152a6635f64a k8-fastbuild-ST-6f89e1bee3ea
aaa26904110821b8e0f87aabfffcfb8e5003a5620aee74de3d7ddea9a654c0f6 k8-opt (host)
d6b1a93e6619d845f29ee752e338ec2636e7fbf4c88e50168602cc21f5ae6f13 k8-opt-exec-2B5CBBC6-ST-5934bb4653e4 (exec)

注意:設定資訊會持續累積,直到下次霧化清除為止。

請使用 bazel config <id> 將設定轉儲到 stdout,以檢查其值。警告:輸出內容過長。

$ bazel config 20222e2616387f00ae3814d79f82a650829d1aea962d558edda5cf54c459f4a2 | wc -l
Loading:
INFO: Displaying config with id 20222e2616387f00ae3814d79f82a650829d1aea962d558edda5cf54c459f4a2
436

連結至這裡的實際輸出內容。

請注意,在實務上,每項設定都是一組字典,每項設定都會涵蓋特定主題。這些片段稱為「片段」,且只有少數可以直接從 Starlark 存取:

$ bazel config 20222e2616387f00ae3814d79f82a650829d1aea962d558edda5cf54c459f4a2 | grep FragmentOptions
FragmentOptions com.google.devtools.build.lib.analysis.PlatformOptions {
FragmentOptions com.google.devtools.build.lib.analysis.ShellConfiguration$Options {
FragmentOptions com.google.devtools.build.lib.analysis.config.CoreOptions {
FragmentOptions com.google.devtools.build.lib.analysis.test.CoverageConfiguration$CoverageOptions {
FragmentOptions com.google.devtools.build.lib.analysis.test.TestConfiguration$TestOptions {
FragmentOptions com.google.devtools.build.lib.bazel.rules.BazelRuleClassProvider$StrictActionEnvOptions {
FragmentOptions com.google.devtools.build.lib.bazel.rules.python.BazelPythonConfiguration$Options {
FragmentOptions com.google.devtools.build.lib.rules.android.AndroidConfiguration$Options {

  1. k8 是現在稱為 x86_64 CPU 架構的舊命名慣例。