RFC-0186:Fuchsia 適用的 Bazel

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

建議將 Fuchsia SDK 和 Bazel 納入 fuchsia.git,以便將 Bazel 納為 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 都已表達對這項計畫的承諾,並願意提供支援。

定義

  • 「In-tree」是指儲存在 fuchsia.git 中的所有內容。
  • 「樹外」(OOT) 是指以 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 - Fuchsia 適用的 Rust
  • brunodalbo - 連線
  • surajmalhotra - 驅動程式架構
  • amathes - Fuchsia PM Lead
  • cphoenix - 診斷
  • akbiggs - Flutter on Fuchsia

社會化:

這個 RFC 的初步社交化提案已由 Fuchsia Build 團隊、Fuchsia SDK 團隊、Fuchsia 的 Toolchain 團隊、Fuchsia EngProd 團隊、Fuchsia 的 Rust 團隊,以及 Fuchsia 的各個代表和主管審查。

設計

這份 RFC 旨在制定專案政策。以下列出這項政策的設計原則。

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

包容性:雖然 Fuchsia 團隊已採用 Bazel,並將持續擴大其使用範圍,並為使用者提供使用 Bazel 的明確路徑,但並未嚴格規定必須使用 Bazel 建構 Fuchsia 軟體。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
  • 建構及測試工作站體驗程式碼
  • 協助 Google 產品組裝作業

其他採用提案

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

除了上述持續進行的「現有採用計畫」外,我們也會在 fuchsia.git 中建立 Bazel 建構樹狀結構,並與 GN 建構樹狀結構並列。Bazel 建構作業可建構及測試已封裝的元件,並組合產品。我們會將邏輯 (Bazel 引導程序、Starlark 規則) 與 Fuchsia Bazel SDK 共用,以便供樹狀結構外開發人員使用。

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

替代文字:從 ninja 平台建構作業流入至 Bazel 組件的樹狀結構內結構 - 在 Bazel 中組合

接著,我們會找出幾個候選元件,以便逐步從 GN/Ninja 平台建構作業提取至 Bazel 平台建構作業,同時保留從相同構件組合出一致的 Fuchsia 映像檔的能力,並保留或改善其他支援的工作流程。

替代文字:從 ninja 平台建構作業將樹狀結構內 Bazel 組合 - 將元件移至 Bazel

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

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

目前的計畫是將 fint 中 GN/Ninja 和 Bazel 呼叫的所有層面都封裝起來,我們發現任何以 fint 實作並因上述封裝而保留的 fx 建構工作流程。

Fuchsia Build 團隊將負責保留編譯器/模型訓練的能力,並與 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 Build 團隊),他們一開始就承諾投入資源,與元件團隊合作,協助 Fuchsia 工程師順利完成這項工作。我們預期 Bazel SDK 整合團隊和 Fuchsia Build 團隊會推動首次遷移至 Bazel 和 SDK,然後根據這項經驗,提供有根據的人力/經費預估值,以便進一步進行遷移。

自動化工具

在功能領域遷移至 Bazel 後,我們會探討如何新增自動檢查功能,確保這些領域日後的成長不會誤設為使用 GN 建構。這個階段會在程序結束前或結束時發生,也就是我們證明 KPI 目標已達成且不會倒退後。

未來可能考量的事項

如果有明確的路線圖,我們日後可能會將 Fuchsia 的 100% 原始碼遷移至 Bazel。在未來,我們預計會推出純 Bazel 建構,並淘汰用於管理建構的 fxfint 指令,改為完全使用 Bazel 命名慣例。

說明文件

我們正在更新 fuchsia.dev 上的說明文件,以便說明如何使用 Bazel 搭配 SDK,並教導相關操作。RFC-139 就是這項作業的一部分。

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

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

請注意,RFC-0153 仍在進行中,這項 RFC 並未取代該 RFC,因為前者建議使用 Fuchsia 平台建構作業所使用的開放原始碼 Ninja 工具的臨時自訂版本。Fuchsia 會持續依賴 Ninja 一段時間,因此我們歡迎您為 Ninja 提供有價值的改善建議。

未知:如果技術上可將 Fuchsia 的所有程式碼移至 Bazel,同時保留良好的使用者體驗,並維持 Bazel 的慣用用法。我們將與建構合作夥伴探討這項可能性,並判斷是否有視線。我們發現,這個未知項目不會阻止我們將 Fuchsia 元件和套件移至 Bazel 的計畫,也不會阻止此 RFC 獲得核准。

功能差異:Bazel 不太支援在相同建構叫用中進行目標設定轉換。舉例來說,如果使用者想將所有可執行檔都建構為「release」,然後將一個可執行檔建構為「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 開發的主要方式,並以與 Google 以外的 Fuchsia 開發人員相同的方式開發 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 ZN 與 Fuchsia GN 之間的合約並非有意簽訂 (Fuchsia 不會只為了外部使用或擴充功能而產生 ZBI)。此 RFC 建議使用套件和產品組合做為合約,以示範所學到的課題 (請參閱 RFC-0072RFC-0095、即將推出的 Fuchsia 平台路線圖)。
  3. 在遷移計畫完成前,請勿開始遷移作業。

Chrome 的 GYP->GN

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

Chrome 之所以決定從 GYP 遷移至 GN,是因為 GYP 版本難以推理,難以解釋,且相當於「gn gen」的時間約為一分鐘。這對 Chrome 團隊來說是重大的生產力損失,因此我們需要其他建構系統。

遷移作業最終成功。我們估計這項工作在約 3 年內完成,耗費了 8 人年。

Chrome 團隊嘗試採用漸進式方法,但在九個月後決定暫停這項工作。他們發現,建構設定中的阻抗不相容是造成增量方法產生摩擦的主要原因。後來,團隊開始同時進行「自底向上」的 GN 建構作業和 GYP 建構作業。首先是資訊機器人,然後是實際的機器人。這項遷移作業擴及各個目標平台 (Linux、Windows、Mac、Android、iOS)。遷移作業之所以成功,其中一個關鍵原因是因為有一位強力推手,並且承諾會將遷移作業完成。

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

  • 由於案例太過籠統,因此很難以簡單易懂的方式說明該如何處理。進行轉換的人員必須幾乎完全瞭解舊版和新版建構系統。幾乎沒有人知道這項資訊。
  • 這類遷移作業需要大量的時間和精力,而且很難長期維持貢獻。
  • 我們可以清楚說明需要執行的順序,並提供方便存取的追蹤和整理功能,讓使用者更輕鬆地協助遷移作業。
  • 為了成功遷移,您必須對使用者給予細心照顧和同理心。在這個遷移作業中,我們需要妥善遷移大量的使用者功能和使用者工作流程。