使用平台進行建構

回報問題 查看原始碼 Nightly · 8.0 . 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel 提供精密的支援功能,可模擬平台工具鍊。將這項功能與實際專案整合,需要程式碼擁有者、規則維護者和核心 Bazel 開發人員之間的仔細合作。

本頁面會概述平台的用途,並說明如何使用這些平台進行建構。

重點摘要:Bazel 的平台和工具鍊 API 已可使用,但在所有語言規則、select() 和其他舊版參照項目更新前,這些 API 無法在所有地方運作。這項工作仍在持續進行中。所有版本都將以平台為基礎。請參閱下文,瞭解您的版本適用於哪些裝置。

如需更正式的文件,請參閱:

背景

平台工具鍊的引入,是為了標準化軟體專案針對不同機器的目標,並使用適當的語言工具進行建構。

這是 Bazel 近期新增的功能。這項功能的靈感來自觀察到語言維護人員以臨時性且不相容的方式執行此操作。舉例來說,C++ 規則會使用 --cpu--crosstool_top 設定建構的目標 CPU 和 C++ 工具鍊。這兩種方法都無法正確模擬「平台」。過去嘗試這麼做時,都會導致不順暢且不準確的建構作業。這些旗標也不會控制 Java 編譯作業,因為 Java 會使用 --java_toolchain 發展出自己的獨立介面。

Bazel 適用於大型、多語言、多平台專案。這需要更有原則地支援這些概念,包括鼓勵語言和專案互通性的明確 API。這就是這些新 API 的用途。

遷移

平台和工具鍊 API 只有在專案實際使用時才會運作。這並非易事,因為專案的規則邏輯、工具鍊、依附元件和 select() 都必須支援這些項目。這需要謹慎的遷移順序,才能讓所有專案及其依附元件正常運作。

舉例來說,Bazel 的 C++ 規則支援平台。但 Apple 規則則不然。您的 C++ 專案可能不會在意 Apple。但其他人可能會。因此,目前還不建議為所有 C++ 版本全域啟用平台。

本頁的其餘部分將說明這個遷移程序,以及您的專案何時及如何配合。

目標

當所有專案都使用以下表單進行建構時,Bazel 的平台遷移作業就會完成:

bazel build //:myproject --platforms=//:myplatform

這表示:

  1. 專案使用的規則可從 //:myplatform 推斷正確的工具鍊。
  2. 專案依附元件使用的規則可從 //:myplatform 推斷正確的工具鍊。
  3. 或者專案依據您的支援 //:myplatform 您的專案支援舊版 API (例如 --crosstool_top)。
  4. //:myplatform 會參照 CPUOS 和其他支援自動跨專案相容性的一般概念的 [通用宣告][Common Platform Declaration]{: .external}。
  5. 所有相關專案的 select() 都會瞭解 //:myplatform 所暗示的機器屬性。
  6. //:myplatform 是在明確且可重複使用的位置定義:如果平台是專屬於您的專案,則會在專案的 repo 中定義;否則,則會在所有可能使用此平台的專案中定義。

達成這項目標後,我們會立即移除舊版 API。這將成為專案選擇平台和工具鍊的標準方式。

我是否應該使用平台?

如果您只想建構或交叉編譯專案,請按照專案的官方文件操作。

如果您是專案、語言或工具鍊維護者,最終都會想支援新的 API。您可以等到全球遷移作業完成後再加入,也可以提早加入,這取決於您的特定價值 / 成本需求:

  • 您可以select()或選擇所需屬性的工具鍊,而非硬式編碼標記 (例如 --cpu)。舉例來說,多個 CPU 可以支援相同的指令集
  • 更正確的版本。如果您在上述範例中使用 --cpu select(),然後新增支援相同指令集的新 CPU,select() 就無法辨識新 CPU。但平台上的 select() 仍會正確。
  • 簡化使用者體驗。所有專案都支援:--platforms=//:myplatform。指令列不需要多個語言專屬標記。
  • 簡化語言設計。所有語言都共用一個通用 API,可用於定義工具鍊、使用工具鍊,以及為平台選取正確的工具鍊。
  • 如果目標與目標平台不相容,則可在建構和測試階段略過

費用

  • 尚未支援平台的依附專案可能無法自動與您的平台搭配運作。
  • 如要讓這些服務正常運作,可能需要額外的臨時維護
  • 新舊 API 共存時,您必須提供更謹慎的使用者指南,以免造成混淆。
  • OSCPU常見屬性的標準定義仍在發展中,可能需要額外的初始貢獻。
  • 特定語言工具鍊的標準定義仍在發展中,可能需要額外的初始貢獻。

API 審查

platform 是一組 constraint_value 目標

platform(
    name = "myplatform",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:arm",
    ],
)

constraint_value 是機器屬性。相同「類型」的值會歸入共同的 constraint_setting 下:

constraint_setting(name = "os")
constraint_value(
    name = "linux",
    constraint_setting = ":os",
)
constraint_value(
    name = "mac",
    constraint_setting = ":os",
)

toolchainStarlark 規則。其屬性會宣告語言的工具 (例如 compiler = "//mytoolchain:custom_gcc")。其供應者會將這項資訊傳遞給需要使用這些工具建構的規則。

工具鍊會宣告可指定的機器 constraint_value (target_compatible_with = ["@platforms//os:linux"]),以及可執行工具的機器 (exec_compatible_with = ["@platforms//os:mac"])。

建構 $ bazel build //:myproject --platforms=//:myplatform 時,Bazel 會自動選取可在建構機器上執行的工具鍊,並為 //:myplatform 建構二進位檔。這就是所謂的工具鍊解析

您可以使用 register_toolchainsWORKSPACE 中註冊可用的工具鍊組合,也可以使用 --extra_toolchains 在指令列中註冊。

如需深入瞭解,請參閱這篇文章

狀態

目前支援的平台因語言而異。所有 Bazel 主要規則都會移至平台。不過,這項程序需要時間。這有三個主要原因:

  1. 您必須更新規則邏輯,才能從新的工具鍊 API (ctx.toolchains) 取得工具資訊,並停止讀取 --cpu--crosstool_top 等舊版設定。這項操作相對簡單。

  2. 工具鍊維護者必須定義工具鍊,並讓使用者存取 (在 GitHub 存放區和 WORKSPACE 項目中)。這在技術上很簡單,但必須以聰明的方式安排,才能維持簡單的使用者體驗。

    您也必須提供平台定義 (除非您為執行 Bazel 的相同機器建構)。一般來說,專案應自行定義平台。

  3. 您必須遷移現有專案。select()轉場效果也必須遷移。這正是最大的挑戰。這對多語言專案來說特別棘手 (如果所有語言都無法讀取 --platforms,專案可能會失敗)。

如果您要設計新的規則集,必須從一開始就支援平台。這樣一來,您的規則就會自動與其他規則和專案相容,隨著平台 API 的普及程度提高,價值也會隨之增加。

常見的平台屬性

OSCPU 等跨專案通用的平台屬性,應在標準的集中位置宣告。這有助於跨專案和跨語言的相容性。

舉例來說,如果 MyAppconstraint_value @myapp//cpus:arm 上有 select(),而 SomeCommonLib@commonlib//constraints:arm 上有 select(),則這些會觸發「arm」模式,但條件不相容。

全球通用的屬性會在 @platforms 存放區中宣告 (因此上述範例的標準化標籤為 @platforms//cpu:arm)。語言通用屬性應在各自語言的存放區中宣告。

預設平台

一般來說,專案擁有者應明確定義平台,以說明他們要為哪些機器建構。然後使用 --platforms 觸發這些事件。

如果未設定 --platforms,Bazel 預設會使用 platform,代表本機建構機器。這會在 @local_config_platform//:host 中自動產生,因此您不需要明確定義。它會將本機機器的 OSCPU 對應至 @platforms 中宣告的 constraint_value

C++

設定 --incompatible_enable_cc_toolchain_resolution 時,Bazel 的 C++ 規則會使用平台選取工具鍊 (#7260)。

也就是說,您可以使用以下方式設定 C++ 專案:

bazel build //:my_cpp_project --platforms=//:myplatform

而非舊版:

bazel build //:my_cpp_project` --cpu=... --crosstool_top=...  --compiler=...

如果您的專案是純 C++,且非 C++ 專案不會依附於此專案,只要 select轉換相容,您就能安全地使用平台。詳情請參閱 #7260 和「設定 C++ 工具鍊」一文。

這個模式預設為停用。這是因為 Apple 專案仍會使用 --cpu--crosstool_top 設定 C++ 依附元件 (示例)。這取決於 Apple 規則遷移至平台的情況。

Java

Bazel 的 Java 規則會使用平台。

這會取代舊版旗標 --java_toolchain--host_java_toolchain--javabase--host_javabase

如要瞭解如何使用設定標記,請參閱 Bazel 和 Java 手冊。詳情請參閱設計文件

如果您仍在使用舊版旗標,請按照問題 #7849 中的遷移程序進行。

Android

設定 --incompatible_enable_android_toolchain_resolution 時,Bazel 的 Android 規則會使用平台選取工具鍊。

這項功能預設為停用。但遷移作業已順利進行。

Apple

Bazel 的 Apple 規則尚不支援平台選取 Apple 工具鍊。

由於這些工具使用舊版 --crosstool_top 設定 C++ 工具鍊,因此也不支援平台啟用的 C++ 依附元件。在遷移完成前,您可以使用平台對應,將 Apple 專案與支援平台的 C++ 混合使用示例

其他語言

如果您要為新語言設計規則,請使用平台選取該語言的工具鍊。如需詳細操作說明,請參閱工具鍊說明文件

select()

專案可以select()constraint_value目標上執行,但無法在完整平台上執行。這是有意為之,讓 select() 支援盡可能多樣的機器。含有 ARM 專屬來源的程式庫應支援所有 ARM 機器,除非有理由需要更具體的支援。

如要選取一或多個 constraint_value,請使用:

config_setting(
    name = "is_arm",
    constraint_values = [
        "@platforms//cpu:arm",
    ],
)

這相當於傳統上在 --cpu 上選取:

config_setting(
    name = "is_arm",
    values = {
        "cpu": "arm",
    },
)

詳情請參閱這篇文章

--cpu--crosstool_top 等上的 select 無法解讀 --platforms。將專案遷移至平台時,您必須將專案轉換為 constraint_values,或是使用平台對應,以便在遷移期間支援這兩種樣式。

轉場

Starlark 轉換可變更建構圖表的部分標記。如果專案使用會設定 --cpu--crossstool_top 或其他舊版標記的轉換,則讀取 --platforms 的規則就不會看到這些變更。

將專案遷移至平台時,您必須將 return { "//command_line_option:cpu": "arm" } 轉換為 return { "//command_line_option:platforms": "//:my_arm_platform" } 等變更,或是使用平台對應,透過遷移視窗支援這兩種樣式。

如何使用現有平台

如果您只想建構或交叉編譯專案,請按照專案的官方文件操作。語言和專案維護者可自行決定如何與平台整合、何時整合,以及整合後可帶來的價值。

如果您是專案、語言或工具鍊維護者,且建構作業不會預設使用平台,您有三個選項 (除了等待全球遷移作業完成):

  1. 為專案的語言開啟「use platforms」標記 (如果有),並進行所需測試,確認您關心的專案是否運作正常。

  2. 如果您關注的專案仍依賴 --cpu--crosstool_top 等舊版標記,請搭配使用 --platforms

    bazel build //:my_mixed_project --platforms==//:myplatform --cpu=... --crosstool_top=...

    這會產生一些維護費用 (您必須手動確認設定是否一致)。但在沒有叛逃轉換的情況下,這應該會正常運作。

  3. 撰寫平台對應,將 --cpu 樣式設定對應至對應平台,反之亦然,以便支援這兩種樣式。

平台對應

平台對應是暫時性 API,可讓平台支援和舊版支援的邏輯在同一個版本中共存,直到後者淘汰為止。

平台對應是將 platform() 對應至相應的舊版標記集合,或反之。例如:

platforms:
  # Maps "--platforms=//platforms:ios" to "--cpu=ios_x86_64 --apple_platform_type=ios".
  //platforms:ios
    --cpu=ios_x86_64
    --apple_platform_type=ios

flags:
  # Maps "--cpu=ios_x86_64 --apple_platform_type=ios" to "--platforms=//platforms:ios".
  --cpu=ios_x86_64
  --apple_platform_type=ios
    //platforms:ios

  # Maps "--cpu=darwin --apple_platform_type=macos" to "//platform:macos".
  --cpu=darwin
  --apple_platform_type=macos
    //platforms:macos

Bazel 會利用這項功能,確保所有設定 (包括平台和舊版設定) 都能在整個建構作業中一致套用,包括轉換

根據預設,Bazel 會從工作區根目錄中的 platform_mappings 檔案讀取對應項目。您也可以設定 --platform_mappings=//:my_custom_mapping

詳情請參閱這裡

問題

如有一般支援服務和遷移時間表相關問題,請與 bazel-discuss@googlegroups.com 或適當規則的擁有者聯絡。

如要討論平台/工具鍊 API 的設計和演進,請與 bazel-dev@googlegroups.com 聯絡。

另請參閱