使用平台進行建構

Bazel 提供複雜的支援,可用於建模平台工具鍊。如要把這個功能整合至實際專案,程式碼擁有者、規則維護人員和核心 Bazel 開發人員之間需格外謹慎地合作。

本頁概述平台的用途,並說明如何透過這些平台建構應用程式。

tl;dr:我們提供 Bazel 的平台和工具鍊 API,但必須等到所有語言規則、select() 和其他舊版參照更新後,才能於任何地方執行。這項工作仍在持續進行中。最終所有建構作業都將以平台為基礎。請參閱下方內容,瞭解建構作業的適用之處。

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

背景

我們推出了平台工具鍊,希望將軟體專案鎖定不同機器,並以合適的語言工具進行建構。

這是 Bazel 最近的新增項目。我們的觀察結果的觀察結果顯示,語言維護人員「已」以臨時、不相容的方式執行此操作。舉例來說,C++ 規則會使用 --cpu--crosstool_top 來設定版本的目標 CPU 和 C++ 工具鍊。這兩種方式都未正確建立「平台」模型一直以來嘗試這樣做都會造成尷尬及不準確的建構。這些標記也無法控制 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 的 [常用宣告][常見平台聲明]{: .external},以及其他支援自動跨專案相容性的一般概念。
  5. 所有相關專案的 select() 都能理解 //:myplatform 隱含的機器屬性。
  6. //:myplatform 是在清楚且可重複使用的位置定義:如果平台專屬於您的專案,其他可能使用該平台的專案則可在專案的存放區中找到。

達到這個目標後,舊版 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")。其提供者會將這項資訊傳送至需要使用這些工具建構的規則。

工具鍊會宣告可指定 (target_compatible_with = ["@platforms//os:linux"]) 的機器 constraint_value,以及其工具可執行的機器 (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(),這些就會觸發其「行為」模式,但有不相容的條件。

系統會在 @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 規則會使用平台選取工具鍊。

這個選項預設為停用。但遷移作業即將順利進行。

蘋果

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

也不支援平台啟用的 C++ 依附元件,因為這些依附元件使用舊版 --crosstool_top 設定 C++ 工具鍊。在進行遷移前,您可以混合 Apple 專案與支援插座的 C++ 以及平台對應 (範例)。

其他語言

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

select()

專案可以針對 constraint_value 目標進行 select(),但無法完成平台。這是刻意設計,讓 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. 針對您專案的語言開啟「使用平台」標記 (如果它們有),然後執行任何測試,看看您重視的專案是否有效。

  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 聯絡,或與適當規則的擁有者聯絡。

如要討論平台/toolchain API 的設計和發展,請與 bazel-dev@googlegroups.com 聯絡。

另請參閱