平台

Bazel 可利用各種版本的建構工具 (例如連接器和編譯器),在各種硬體、作業系統和系統設定上建構及測試程式碼。Bazel 具有限制平台的概念,可以協助管理相關的複雜作業。限制是建構環境或實際工作環境可能不同的維度,例如 CPU 架構、是否存在 GPU,或系統安裝的編譯器版本等。平台是這些限制的已命名選項集合,代表某些環境中可用的特定資源。

將環境建立為平台模型,可協助 Bazel 自動為建構動作選取合適的工具鍊。平台也可以與 config_setting 規則搭配使用,以寫入可設定的屬性

Bazel 可識別平台可能提供的三個角色:

  • 主機:Bazel 本身執行的平台。
  • 執行 - 建構工具用於執行建構動作以產生中繼和最終輸出的平台。
  • 「Target」:最終輸出的所在平台。

Bazel 支援下列與平台相關的建構情境:

  • 單一平台建構 (預設):主機、執行和目標平台相同。例如,在搭載 Intel x64 CPU 的 Ubuntu 上建構 Linux 執行檔。

  • 跨編譯版本:主機和執行平台相同,但目標平台不同。例如,建構在 macOS 在 MacBook Pro 上執行的 iOS 應用程式。

  • 多平台版本:主機、執行和目標平台完全不同。

定義限制與平台

平台的可能選擇空間是由 BUILD 檔案中的 constraint_settingconstraint_value 規則定義。constraint_setting 會建立新維度,而 constraint_value 則會為特定維度建立新值,同時有效定義列舉及其可能的值。舉例來說,下列 BUILD 檔案的程式碼片段針對系統的 glibc 版本設有一項限制,其中包含兩個可能的值。

constraint_setting(name = "glibc_version")

constraint_value(
    name = "glibc_2_25",
    constraint_setting = ":glibc_version",
)

constraint_value(
    name = "glibc_2_26",
    constraint_setting = ":glibc_version",
)

限制和參數值可以透過工作區的不同套件定義。這類函式是由標籤參照,受到一般的瀏覽權限控制影響。如果瀏覽權限允許,您可以定義自己的值,擴充現有限制設定。

platform 規則導入了具有特定限制值的新平台。以下說明會建立名為 linux_x86 的平台,並表示該平台描述了在 glibc 2.25 版本,且在 x86_64 架構上執行 Linux 作業系統的任何環境。如要進一步瞭解 Bazel 的內建限制,請參閱下文。

platform(
    name = "linux_x86",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":glibc_2_25",
    ],
)

一般實用的限制和平台

為了維持生態系統的一致性,Bazel 團隊負責維護一個存放區,並針對最熱門的 CPU 架構和作業系統設下限制定義。這些都位於 https://github.com/bazelbuild/platforms

Bazel 隨附的特殊平台定義如下:@local_config_platform//:host。這是自動偵測的主機平台值,代表執行 Bazel 的系統自動偵測平台。

指定建構的平台

您可以使用下列指令列旗標為建構作業指定主機和目標平台:

  • --host_platform - 預設為 @bazel_tools//platforms:host_platform
  • --platforms - 預設為 @bazel_tools//platforms:target_platform

略過不相容的目標

針對特定目標平台進行建構時,通常會略過無法在該平台上運作的目標。舉例來說,在具有 //... 的 Linux 電腦上建構時,Windows 裝置驅動程式可能會產生許多編譯器錯誤。使用 target_compatible_with 屬性向 Bazel 說明您程式碼的目標平台限制。

最簡單的使用這項屬性,可將目標限制為單一平台。系統不會針對未滿足所有限制的平台建構目標。以下範例將 win_driver_lib.cc 限制為 64 位元 Windows。

cc_library(
    name = "win_driver_lib",
    srcs = ["win_driver_lib.cc"],
    target_compatible_with = [
        "@platforms//cpu:x86_64",
        "@platforms//os:windows",
    ],
)

:win_driver_lib 與使用 64 位元 Windows 進行建構相容,而且與所有其他版本都不相容。不相容性會延遲轉換。任何間接依附於不相容目標的目標都會視為不相容。

系統何時略過目標?

如果目標遭判定為不相容,且已包含在目標模式擴充中,系統就會略過這些目標。舉例來說,下列兩個叫用會略過目標模式擴充時找到的任何不相容的目標。

$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all

如果在指令列中使用 --expand_test_suites 指定 test_suite,系統也會略過 test_suite 中不相容的測試。也就是說,指令列的 test_suite 目標行為與 :all... 類似。使用 --noexpand_test_suites 可防止擴充,並導致含有不相容測試的 test_suite 目標也不相容。

如果在指令列上明確指定不相容的目標,將導致錯誤訊息和建構作業失敗。

$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully

限制更明確

如需更靈活地表達限制,請使用沒有平台支援的 @platforms//:incompatible constraint_value

搭配使用 select()@platforms//:incompatible 即可表達更複雜的限制。例如,您可以將其用於實作基本的「或」邏輯。以下標示與 macOS 和 Linux 相容的程式庫,但沒有其他平台。

cc_library(
    name = "unixish_lib",
    srcs = ["unixish_lib.cc"],
    target_compatible_with = select({
        "@platforms//os:osx": [],
        "@platforms//os:linux": [],
        "//conditions:default": ["@platforms//:incompatible"],
    }),
)

上述資料的解讀方式如下:

  1. 如果指定 macOS,目標則沒有限制。
  2. 如果指定 Linux,目標則沒有任何限制。
  3. 否則,目標就會具有 @platforms//:incompatible 限制。由於 @platforms//:incompatible 並非任何平台的一部分,因此認定目標不相容。

如要讓限制更容易閱讀,請使用 skylibselects.with_or()

您可以透過類似的方式呈現反向相容性。以下範例說明的程式庫與 ARM「以外」的所有項目相容。

cc_library(
    name = "non_arm_lib",
    srcs = ["non_arm_lib.cc"],
    target_compatible_with = select({
        "@platforms//cpu:arm": ["@platforms//:incompatible"],
        "//conditions:default": [],
    ],
)

使用 bazel cquery 偵測不相容的目標

您可以使用 bazel cqueryStarlark 輸出格式中的 IncompatiblePlatformProvider,區分不相容的目標和相容的目標。

這可用於篩除不相容的目標。以下範例只會列印相容目標的標籤。系統不會列印不相容的目標。

$ cat example.cquery

def format(target):
  if "IncompatiblePlatformProvider" not in providers(target):
    return target.label
  return ""


$ bazel cquery //... --output=starlark --starlark:file=example.cquery

已知問題

不相容的目標會忽略瀏覽權限限制