RFC-0186:Fuchsia 適用的 Bazel

RFC-0186:Fuchsia 適用的 Bazel
狀態已接受
區域
  • 建構
說明

建議將 Bazel 納入 fuchsia.git,並採用為 Fuchsia 元件的主要建構系統。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2022-04-21
審查日期 (年-月-日)2022-08-29

摘要

我們的計畫是將 Fuchsia SDK 和 Bazel 導入 fuchsia.git,藉此匯集並採用 Bazel 做為 Fuchsia 元件的主要建構系統。

Fuchsia 團隊致力於完成這項遷移作業。具體來說,Fuchsia 建構團隊、Fuchsia Bazel SDK 整合團隊、Fuchsia 平台基礎架構、Fuchsia 軟體組裝、Fuchsia TPM 團隊和 Fuchsia DevRel 都已承諾會交付並支援這項計畫。

定義

  • 「樹內」是指儲存在 fuchsia.git 中的所有內容。
  • 「樹外」是指以 Fuchsia 為目標,並以 Fuchsia SDK 為基礎建構的程式碼,而非平台原始碼,且儲存在 fuchsia.git 以外的位置。舉例來說,Intel WLAN 驅動程式庫的建構範例位於獨立存放區,並使用 Fuchsia Bazel SDK。
  • Bazel:軟體開發專用的開放原始碼建構與測試工具。

提振精神

自 2022 年第 1 季起,Fuchsia 平台 (即 fuchsia.git 中的程式碼) 建構作業會使用 GN/Ninja。2021 年,我們加快了以 SDK 為基礎的開發作業,以償還技術債並實現未來策略。Fuchsia 選擇 Bazel 做為 SDK 開發的明確路徑,並將其用於現有和新的來源基礎。

我們發現,無論元件和產品開發人員在哪個樹狀結構/存放區工作,建構及使用 Fuchsia 的許多用途都相同。例如:將原始碼編譯為元件,並將該元件及其資產封裝到 Fuchsia 套件中、在目標上執行該軟體、組裝產品、產生符號、串流記錄等。我們致力於整合 Bazel 和 SDK 工作流程及實作項目,以降低複雜度和成本。

為了對樹狀結構外開發人員產生同理心,並建立及提供優異的 Bazel + SDK 體驗,Fuchsia 團隊本身必須每天使用 SDK 和 Bazel 整合功能,並將其納入支援完善的工作流程。

利害關係人

主持人:rlb

審查者:

  • digit - Fuchsia 的建構團隊
  • chaselatta - Fuchsia 的 Bazel SDK 團隊
  • mangini - Fuchsia 的 Bazel SDK 團隊和 Fuchsia DevRel
  • nsylvain - Fuchsia 的 EngProd 團隊
  • abarth - Fuchsia 架構

已諮詢:

  • aaronwood - Product Assembly
  • awolter - Product Assembly
  • dannyrosen - Eng Excellence
  • keir - Pigweed
  • tmandry - Rust for Fuchsia
  • brunodalbo - Connectivity
  • surajmalhotra - Driver Framework
  • amathes - Fuchsia PM Lead
  • cphoenix - Diagnostics
  • akbiggs - Flutter on Fuchsia

社交:

這項 RFC 的初步提案經過 Fuchsia Build 團隊、Fuchsia SDK 團隊、Fuchsia Toolchain 團隊、Fuchsia EngProd 團隊、Fuchsia Rust 團隊,以及 Fuchsia 各個代表和主管的審查。

設計

這項 RFC 的目的是制定專案政策。以下是這項政策的設計原則清單。

漸進式:我們會一次遷移一個元件,並在過程中學習。

包容性:雖然 Fuchsia 團隊採用 Bazel,並會持續擴大 Bazel 的使用範圍,為使用者建立 Bazel 的明確路徑,但使用 Bazel 建構 Fuchsia 軟體並非嚴格要求。IDK 必須繼續與建構系統無關。IDK

我們也秉持著「建構系統的維度可與來源存放區的維度正交」原則運作。將建構目標遷移至 Bazel 和 SDK 時,不必將程式碼遷移至其他存放區。

最終,我們希望以多個專案的形式組織 Fuchsia 開發作業,每個專案都會將 Fuchsia SDK 做為輸入內容,並產生多個套件或其他二進位檔構件做為輸出內容,這些構件可組合成 Fuchsia 系統映像檔。這些專案可能由 Fuchsia、合作夥伴或第三方開發人員擁有。這些專案的大小也可能不同,從提供單一二進位檔的小型專案,到提供 Fuchsia 平台相當大一部分的大型專案 (例如 fuchsia.googlesource.com/platform.git) 都有。隨著情況越來越接近,我們可以決定如何將程式碼整理到專案中,以盡量提高效率。

這項 RFC 說明朝向最終目標邁出的重要一步,也就是重構大部分的 Fuchsia 開發作業,並將其託管在 Fuchsia SDK 上。重新託管至 Fuchsia SDK 後,我們就能更彈性地將開發作業劃分為多個專案。

實作

現有採用計畫

我們已開始評估及採用 Bazel 和 SDK,以推動下列事項:

  • 建構及測試簡單但可負載的驅動程式庫,並納入 Workstation 中
  • 建構並測試簡單但使用者可存取的元件,並將其併入 Workstation
  • 建構及測試特定數量的驅動程式 (數量會持續增加)
  • 建構及測試範例和其他專案,協助開發人員開始為 Fuchsia 進行開發
  • 在 Fuchsia 嵌入器上建構及測試 Flutter
  • 建構及測試 Workstation Experiences 程式碼
  • Google 產品的硬碟產品組裝

其他採用提案

在繼續下文之前,我們會先收集證據,證明 Bazel SDK 展現最低可行性和足夠的功能,可支援最終供部分使用者使用的軟體和系統。上述簡單的驅動程式庫和簡單的元件將使用 SDK 建構,並發布至全球整合平台,然後納入目前的 Workstation 產品組裝程序。接著,Fuchsia 工程委員會和 Fuchsia 安全性團隊會審查 Bazel SDK 中的程式碼,以及儲存簡單驅動程式庫和簡單元件的存放區中的設定,還有發布這些預先建構元件的機制,以供 Workstation 建構程序使用。只有在通過這些審查,且使用者收到附有簡易驅動程式庫和簡易元件的產品後,我們才會繼續處理。

除了上述「現有採用計畫」外,我們也會在 fuchsia.git 中建立 Bazel 建構樹狀結構,與 GN 建構樹狀結構並行。Bazel 建構作業將可建構及測試封裝元件,並組裝產品。我們會與樹狀結構外開發人員分享邏輯 (Bazel 啟動程序、Starlark 規則)。

我們會先在 fuchsia.git 中,使用 Bazel 和 SDK 實作產品組裝用途。我們會從流程的結尾開始回溯,也就是說,我們可以提供線性 GN/Ninja -> Blaze 流程。fx build

替代文字:
樹狀結構內流程,從 Ninja 平台建構到 Bazel 組件 - Bazel 中的組件

接著,我們會從 GN/Ninja 平台建構中逐步擷取幾個候選元件,並將其移至 Bazel 平台建構,同時保留從相同構件組裝連貫式 Fuchsia 映像檔的能力,並保留或改善其他支援的工作流程。

替代文字:
樹狀結構內流程,從 Ninja 平台建構作業到 Bazel 組件 - 將元件移至 Bazel

我們在實作這些第一候選元件的支援功能時,會監控 KPI (如下所述),並與早期採用者互動,確保他們的工程生產力不會倒退。我們會隨時向 Fuchsia 團隊回報狀態和測量結果。

我們預期 fuchsia.git 貢獻者會使用 fx 做為前端來驅動建構作業,而 fx 會在幕後管理 Bazel 和 GN/ninja 的呼叫。在轉換期間,保留 fx setfx build 等前端,有助於封裝遷移作業的詳細資料,並保留工作流程。

目前的計畫是將叫用 GN/Ninja 和 Bazel 的所有層面封裝在 fint 內,並注意以 fint 實作的任何 fx 建構工作流程也會因上述封裝而保留。

Fuchsia 建構團隊將負責保留編譯器/模型訓練能力,並與 GN 建構作業合作,協助保留語料庫大小。

將 fuchsia.git 中的元件遷移至 Bazel,與在存放區之間移動元件不同。遷移至 Bazel 的 fuchsia.git 元件可以保留在 fuchsia.git 中。本 RFC 不包含存放區遷移作業。 不過,在將所有目標元件遷移至 Bazel 和 SDK 之前,我們打算重新檢視建構架構,並與 FEC 合作,判斷是否要將 Bazel 和 SDK 建構的任何元件移出 fuchsia.git 樹狀結構。

KPI

我們建議採用下列 KPI 來評估這項工作:

  • 透過問卷調查評估開發人員滿意度
  • 建構時間為空值
  • 設定的完整建構時間,也就是預先提交建構工具的瓶頸
  • 該設定的預先提交測試時間

對於「空值建構時間」(瞭解啟動建構系統本身延遲時間的方法之一),我們會從整體開發人員滿意度和生產力來看待這個問題。除非我們判定空值建構時間是大幅降低開發人員滿意度和生產力的因素,否則我們不會允許空值建構時間回歸 50%。

對於「設定的完整建構時間」和「預先提交測試時間」,我們建議 KPI 的暫時性迴歸幅度不超過 10%,並期望最終能改善所有 KPI。

員工

這項工作的員工和資金細節待定,不在本 RFC 的討論範圍內。不過,我們認為,制定人員配置和資金計畫,對於軟體成功演進至 SDK 和 Bazel 至關重要。Fuchsia 有兩個團隊 (Bazel SDK 整合團隊、Fuchsia 建構團隊),他們最初承諾會投入資源,與元件團隊合作,協助 Fuchsia 工程師順利完成這項工作。我們預期 Bazel SDK 整合團隊和 Fuchsia 建構團隊會推動首次遷移至 Bazel 和 SDK 的作業,並根據這些經驗,為後續遷移作業提供有根據的人員/資金預估。

自動化工具

將功能領域遷移至 Bazel 的作業有重大進展後,我們會探討如何新增自動檢查,確保這些領域日後的成長不會意外設定為使用 GN 建構。這個階段會在程序即將結束或結束時進行,也就是在我們證明已達成 KPI 目標且未退步之後。

未來可能需要考慮的事項

如果前景明朗,我們可能會在日後將 Fuchsia 的原始碼 100% 遷移至 Bazel。在未來的潛在情境中,我們預計會採用純 Bazel 建構作業,並淘汰管理建構作業的 fxfint 指令,改為完全以 Bazel 命名法管理項目。

說明文件

我們正在根據 RFC-139 更新 fuchsia.dev 上的說明文件,說明如何搭配 Bazel 使用 SDK。

我們將在 fuchsia.dev 上更新 Fuchsia 貢獻者適用的文件,說明何時及如何使用 Bazel 樹狀結構內建構。這份文件將提供何時設定要以 Bazel 或 GN 建構元件的指南,以及供貢獻者參考的如何執行建構作業指南。這份文件也會公開。

缺點、替代方案和未知事項

我們注意到 RFC-0153 提案使用 Fuchsia 平台建構作業所用的開放原始碼 Ninja 工具暫時自訂版本,目前仍在進行中,且未被本 RFC 取代。Fuchsia 仍會繼續使用 Ninja 一段時間,因此 Ninja 的生活品質改善措施十分有價值,我們也樂於採用。

未知:如果技術上可行,可將所有 Fuchsia 程式碼移至 Bazel,同時維持良好的使用者體驗,並符合慣用的 Bazel 用法,我們會與建構合作夥伴探討這項潛在商機,並判斷是否能實現。我們注意到,這個未知問題不會阻礙我們將 Fuchsia 的元件和套件移至 Bazel,也不會阻礙這項 RFC 獲得核准。

功能差異:Bazel 對於同一建構調用中的目標設定轉換支援不佳。舉例來說,如果使用者想將所有可執行檔建構為「發布」,然後將一個可執行檔建構為「asan」,則需要兩次 bazel build 呼叫。我們認為這不會造成風險或阻礙,但這與 Fuchsia 現有的 GN 基礎變體系統不同。

可能風險:我們知道 Bazel 內建的 C/C++ 規則有其限制,可能不夠彈性,無法建構低階 Fuchsia 程式庫和二進位檔。根據 Bazel 團隊對 Fuchsia 和公開路線圖的更新,將 Bazel C/C++ 移植到社群擁有及維護的 Starlark 規則,是首要任務。概念已充分驗證,大部分風險都已排除。

不明:Bazel 檔案系統沙箱的影響,以及正確性/密封性之間的淨結果取捨。Bazel 會使用檔案系統沙箱和符號連結,確保增量正確性和密封性。據瞭解,這會在一般建構工作站上增加最多 10% 的清除建構工作負載,並延長建構時間。我們預期,當與遠端建構執行作業搭配使用,以提供更佳的快取使用率、提早截斷和淺層建構時,密封性帶來的效益將遠遠超過差異。不過,如果我們發現密封性成本高於預期,且預期效能優勢無法抵銷成本,就會考慮停用沙箱 (即 --spawn_strategy=local )。

不明:Fuchsia 團隊將獲得 Bazel 上游擁有者提供的支援等級。我們沒有理由相信我們不會獲得支援,而這項 RFC 的目標之一,就是與 Bazel 擁有者建立更強大的合作關係。我們與 Bazel 團隊的初步會議和互動非常有效率,他們也樂於瞭解我們的需求和觀察結果。我們向 Bazel 團隊提出的問題很快就能得到解答。我們相信,隨著 Fuchsia 持續採用 Bazel 做為 SDK (RFC-139),並證明自己是 Bazel 的優質客戶,Bazel 團隊將會持續提供支援並積極參與。

不明:我們將如何使用 Bazel 和 Fuchsia SDK 編譯 Rust 程式碼。我們發現 Bazel 正在積極開發 Rust 支援功能,但我們需要測試這項功能,並瞭解是否符合 Fuchsia 的需求。我們預計會發布後續 RFC,說明如何使用 Bazel 和 Fuchsia SDK 建構 Rust 程式碼。這項工作將與 Fuchsia 上的 Rust 團隊密切合作。

不明、待定:GN/Ninja 建構的構件與 fuchsia.git 中以 Bazel 建構的封裝元件之間的確切介面,以便組合成產品映像檔。我們預計會擴大產品組裝範圍來解決這個問題,詳細資訊待定。

不明:Fuchsia 團隊正在評估如何支援 Windows 做為開發人員主機環境,這會對 Fuchsia 支援以 SDK 為基礎的開發 (包括使用 Bazel) 方式,提出新的要求。我們尚未取得所有這些要求。不過,我們注意到 Bazel 支援 Windows 做為開發人員主機,目前沒有理由相信 Bazel 無法在 Windows 上運作。如果發生這類阻礙,我們會與 Bazel 團隊密切聯絡。

不明:基礎架構中的測試可能或可能不會由 bazel test 驅動。這不會阻礙 RFC,因為我們主要專注於使用 Bazel 進行編譯。

替代方案:繼續使用現今的 GN/Ninja 建構版本,用於 fuchsia.git 中的元件。我們持續資助平行作業,並無法從 Bazel 帶來的工程生產力優勢中獲益,同時與開發人員生態系統的同理心差距也持續存在。此外,平台建構維護人員表示,持續依賴 GN/Ninja 會造成責任問題,因為這些系統無法保證密封的乾淨建構或正確的增量建構。

替代方案:重新考慮 RFC-0139 中採用 Bazel 的決定,改用其他建構系統,然後讓樹狀結構內和樹狀結構外的內容都與該建構系統保持一致。由於沒有重新考慮 RFC-0139 的依據,我們拒絕這項替代方案。

替代方案:除了在 fuchsia.git 中採用 Bazel 和 SDK,我們也可以優先將元件程式碼從 fuchsia.git 移至由 Bazel 和 SDK 支援的不同存放區。這些存放區之間的整合一律只會透過預先建構完成。最終結果相同:Fuchsia 團隊已採用 Bazel 和 SDK 做為 Fuchsia 的主要開發方式,且開發 Fuchsia 的方式與 Google 外部的 Fuchsia 開發人員相同。我們曾考慮這個選項,但部分團隊表示希望能夠在同一次提交中,變更可透過 SDK 存取的程式碼 (例如介面) 和元件程式碼。我們注意到,部分團隊已計畫採用 Bazel 和 SDK,方法是將程式碼移至 fuchsia.git 以外的存放區。

替代方案 (已考量但遭拒):我們將元件移出樹狀結構,以便使用 SDK 和 Bazel 建構這些元件,而非為 fuchsia.git 內的程式碼提供兩個建構系統。這樣做也能達成相同的長期目標 (使用 SDK 和 Bazel 建構更多程式碼),但我們認為這個情境需要更長的時間才能達成目標。此外,這也會導入多個變數 (將程式碼的建構作業遷移至 Bazel + SDK、將程式碼遷移至其他存放區),但我們希望一次只變更一個變數。我們建議先將元件的建構作業變更為 Bazel 和 SDK,然後視需要將元件的程式碼移至其他存放區。

既有技術和參考資料

使用或遷移至 Bazel 的其他範例專案

Bazel 的使用者社群不斷成長,Android 開放原始碼專案先前使用 Ninja 和 Make 的組合,現在則要遷移至 Bazel。Bazel 是 Google 許多成功開放原始碼專案 (例如 Abseil 和 Tensorflow) 的建構系統。

其他建構系統遷移作業

Fuchsia 的 ZN->GN

Fuchsia 執行的另一個建構系統遷移作業 (ZN->GN 遷移作業,又稱「建構統一」) 值得參考。

在建構統一前,Fuchsia 有兩個以 GN/Ninja 為基礎的建構,ZN/Ninja 建構作業會先執行並建構部分構件,接著 GN/Ninja 建構作業會執行並建構其他構件。您可以在 GN 中使用 ZN 輸出內容,但反之則不行。

ZN 和 GN 之間的界線是根據 ZBI 內容等構件劃定。這個介面並不理想,因為它會阻礙使用在 GN 中建構的構件 (例如 FIDL、元件、套件、Rust 支援),產生在 ZN 中建構的構件 (例如驅動程式、早期啟動程式)。

我們曾提議將 GN 構件遷移至 ZN,但後來發現不可行。 而是將 ZN 構件移至 GN。我們逐步驗證這項構件遷移程序,產生建構結果的「摘要資訊清單」,並確保單一遷移步驟不會意外變更資訊清單。當 ZN 建構版本變成空白 (未貢獻給上述資訊清單) 並隨後移除時,這項工作即告結束。

汲取的經驗教訓:

  1. 在遷移期間維持重要工作流程的連續性。
  2. 在分階段遷移時,請使用明確且有意的合約。與 Fuchsia GN 簽訂的 Fuchsia ZN 合約並非有意為之 (Fuchsia 不會只為外部使用或擴充功能製作 ZBI)。這項 RFC 建議使用套件和產品組裝做為合約,以展現所學經驗 (請參閱 RFC-0072RFC-0095 和即將推出的 Fuchsia 平台路線圖)。
  3. 請先規劃好遷移作業的完成方式,再開始遷移。

Chrome 的 GYP->GN

Fuchsia 團隊成員參與的另一個建構系統遷移作業,是 Chrome 從 GYP 遷移至 GN。

Chrome 決定從 GYP 遷移至 GN,是因為 GYP 建構難以推論、難以說明,而且「gn gen」的對等項目大約需要一分鐘。這對 Chrome 團隊的生產力造成重大影響,因此需要其他建構系統。

遷移作業最終順利完成。我們估計這項作業耗費超過 8 年的人力,歷時約 3 年。

Chrome 團隊嘗試採用漸進式做法,但九個月後決定暫停這項工作。他們發現建構設定中的阻抗不相符,是造成增量方法摩擦的主要原因。稍後,團隊開始「由下而上」建構 GN,與 GYP 建構作業並行。先使用 FYI 機器人,然後再使用真正的機器人。這項遷移作業已擴展至目標平台 (Linux、Windows、Mac、Android、iOS)。遷移作業之所以成功,主要原因之一是我們有堅強的擁護者,致力於完成這項作業。

我們從這次遷移作業中學到的經驗:

  • 由於情況太過一般,很難以簡單易懂的指示說明該怎麼做。進行轉換的人員幾乎必須完全瞭解新舊建構系統。幾乎沒有人知道這項知識。
  • 這類遷移作業需要投入大量心力,而且長期維持貢獻可能很困難。
  • 我們可清楚說明遷移作業的順序,並提供容易存取的追蹤和整理功能,讓使用者更輕鬆地協助遷移。
  • 遷移作業能否成功,取決於您是否能設身處地為使用者著想。這次遷移作業需要妥善遷移大量使用者功能和使用者工作流程。