定義 Bazel 規則、巨集和函式的樣式指南和最佳做法

總覽

本頁面提供撰寫規則、巨集和函式的 Fuchsia 專屬樣式和最佳做法。這些項目一律在.bzl 檔案中定義,相關指南也適用於此。此外,BUILD.bazel 檔案中與目標相關的指引,也適用於規則和巨集定義的目標。

本頁是 Bazel 樣式指南和最佳做法的一部分。

判斷是否適合使用新的巨集和函式

如 Bazel 樣式指南所述,Fuchsia 偏好使用 DAMP (描述性且有意義的片語) BUILD 檔案,而非 DRY (不要重複自己)。

具體來說,Fuchsia 建構作業在 Bazel 中使用特定區域的巨集和函式,遠比在 GN 中使用這類範本的頻率低。

使用共用的靜態清單,確保項目必須保持同步 (例如常見的依附元件),而不是編寫特定區域的巨集。

雖然區域專屬範本可減少初始建立目標時的打字量,但由於區域專屬巨集會隱藏個別目標,因此會造成維護和遷移問題,特別是自動化工具。如果您認為使用特定區域的巨集和函式能帶來顯著效益 (根據過去經驗,門檻很高),請諮詢建構團隊。

盡可能使用現有的巨集和規則

如果這類巨集或規則的使用範圍可能很廣,這項重要性就會提高。

如果您的需求僅限於下列項目,請考慮是否能使用現有巨集和/或規則達成:

  • 正在生成中繼資料

  • 強制執行屬性值

  • 例如,盡量減少來電者必須指定的屬性數量

在上述前兩種情況中,請特別考慮是否可使用 Bazel 查詢、SHAC 規則、測試或其他機制來滿足需求。您可以在依附元件樹狀結構或目錄樹狀結構中定義的所有目標上執行 Bazel 查詢。請編寫一項測試,執行查詢並檢查結果。如果您的用途需要額外屬性,請考慮使用標記。

使用現有規則和巨集的原因包括:

  • 開發人員更容易瞭解,適應期也較短

    • 熟悉 Bazel 的開發人員可以立即瞭解目標。

    • 團隊中某部分的開發人員可以瞭解程式碼庫其他部分的目標。

  • AI 較有可能瞭解及產生使用常見規則和巨集的 Bazel 檔案

  • 減少 load() 陳述事項

    • 內建 ID 不需要任何載入陳述式。

    • 檔案中其他目標可能已載入其他目標。

  • 減少發生錯誤的機會

    • 舉例來說,只有在遍歷所有相關目標時,層面才能正常運作。自訂巨集或規則可導入不會遵循的路徑。請參閱「使用標準屬性名稱」。

建議使用符號巨集,而非舊版巨集

建議您編寫符號巨集,這類巨集是使用 macro() 定義,而非舊版巨集 (以 def 定義的 Python 類函式,會建立目標)。符號巨集可提供更清楚的屬性和屬性類型說明文件、對屬性執行類型檢查,並確保標籤是在呼叫網站評估。此外,這些巨集也支援屬性繼承 (透過 inherit_attrs)。如需更多背景資訊,請參閱「為何不應使用舊版巨集」。

請勿在符號巨集的實作函式中指定引數的預設值,因為預設值是由 attrs 項目定義,且系統會為每個屬性提供值。

在某些情況下,必須在符號巨集周圍使用舊版巨集包裝函式,但對大多數開發人員來說,這種情況應該非常罕見。

檢查巨集定義的目標是否可見及可存取

總覽

為了方便查看,您可以將舊版巨集視為在例項化的位置展開。在 BUILD.bazel 檔案中使用時,舊版巨集定義的目標實際上是在該檔案中定義。結果:

  • 定義目標的預設 visibility 與例項化套件相同,包括套件 default_visibility (如有指定)。

  • 巨集可使用 (例如新增至 deps) 任何可供例項化套件使用的目標。

    • 定義舊版巨集的 .bzl 檔案位置無關緊要。

不過,為了方便查看,請將符號巨集定義的目標視為與定義巨集的 .bzl 檔案位於同一個套件 (目錄) 的 BUILD.bazel 檔案中。因此:

  • 定義目標的預設 visibility 是包含 .bzl 檔案的套件 (目錄)。

  • 巨集可以使用 (例如新增至 deps) 包含 .bzl 檔案的套件 (目錄) 可見的任何目標。

    • 舉例來說,這項功能對於 fidl_library() 新增的 FIDL 繫結支援程式庫很有用。

    • 但對於 HLCPP 支援程式庫允許清單等項目而言,這會造成問題。

    • 詳情請參閱問題 446911800。

指定巨集中定義目標的瀏覽權限

公開目標

將傳遞至巨集的 visibility 屬性轉送至巨集定義的主要目標,也就是 name 傳遞的目標。視情況而定,visibility 屬性也可能會轉送至巨集 doc 字串中提及的其他已定義公開目標。

私人目標

在符號巨集中,所有其他定義目標的顯示狀態預設為 ["//visibility:private"]。不過,如果是舊版巨集,則必須為舊版巨集定義的所有目標指定可見性。

為舊版巨集定義的所有目標指定瀏覽權限

針對未使用傳遞至巨集的 visibility 屬性的所有目標,指定 visibility = ["//visibility:private"]。這是必要步驟,可避免系統在指定時預設為套件的 default_visibility。

使用標準屬性名稱

在巨集和規則中使用標準屬性名稱。舉例來說,請使用 "deps"、"data" 或 "tools",而非 "images" 或 "scripts"。請參閱一些普遍適用的屬性。

可能原因包括:

  • 為了方便閱讀及其他類似原因,請參閱「盡可能使用現有巨集和規則」。

  • 只有在遍歷所有相關目標時,層面才能正常運作,且巨集通常會設定為套用至 "deps" 和其他常見屬性 (視情況而定)。不過,他們可能不瞭解 "rust_deps" 等屬性,如果無法套用至該屬性,可能會排除與該方面相關的目標。

需要具名引數

公開函式和舊版巨集 (函式的特殊類別) 一般應宣告僅限關鍵字的引數 (所有引數都會在 *, 後方宣告)。如果函式最多只有幾個引數,且引數可從符號名稱清楚辨識,且引數不會因重構/重新排序等原因而誤用在錯誤位置,則可例外處理。布林引數和具有預設值的引數一律應顯示在 * 之後。

雖然這對程式碼集其他部分使用的符號最為重要,但這也適用於所有 .bzl 檔案中的公開符號。

這有助於強制執行 Bazel .bzl 樣式指南的指引,即「呼叫巨集時,請只使用關鍵字引數。這與規則一致,且大幅提升可讀性。"

宣告巨集使用的所有引數

如果巨集 (選擇性) 使用引數,請在巨集實作的參數清單中明確宣告該引數,而不是從 kwargs 擷取。舉例來說,請避免以下情況:

# Do NOT do this:
testonly = kwargs.get("testonly", False),

宣告引數可清楚指出哪些引數與巨集實作相關 (例如,與巨集呼叫的巨集相比),並提供單一位置來查看預設值。對於舊版巨集,這項功能也會確保引數已記錄在文件中。(這主要與 Fuchsia Bazel SDK 相關)。

與任何其他引數一樣,但特別是所有建構規則通用的屬性和所有測試規則通用的屬性 (_test),您必須確保將引數傳遞至所有支援該引數的巨集和規則,因為這些引數不會位於 **kwargs 中。

留言

  • 為所有公開函式 (開頭不是底線的函式) 提供函式層級的註解。

  • 為所有規則和巨集提供 doc 字串。

  • 為所有規則和巨集屬性提供 doc 字串。

    • 如果私有屬性 (開頭為底線的屬性) 的意義可從 default 值中明顯看出,則可省略 doc 字串。

doc strings

  • 在 Fuchsia 平台中,doc 字串應在來源檔案中讀取,而非在某些產生的說明文件中讀取。因此,請優先最佳化這項功能,而非某些產生的文件外觀。

  • 長 doc 字串:

    • 建議在合理情況下,將頂層單一句子說明完全寫在與 doc= 相同的行上。

    • Bazel沒有嚴格的行長度限制。

    • 如果需要多行,請使用三引號撰寫多行字串。

    • 請避免附加一般字串。

  • 多行 doc 字串

    • 在與 doc 引數 (doc = """Begin the comment...) 相同的行中,開始多行字串。

    • 在 doc 下的 d 開始後續行,類似於 Python 註解在第一個 " 下方開始下一行。

    • 這項設定會盡量確保一致性和可讀性,但生成文字可能不盡理想。

    • 在與 doc 對齊的獨立行上,以三引號 (""") 結尾多行字串。

規則和巨集實作函式名稱

使用開頭底線為 rule() 和 macro() 執行個體命名 implementation 函式,後接規則或函式名稱,並以 _impl 結尾。

在巨集中參照目標名稱時使用變數

如果巨集定義目標,然後在另一個目標中依附該目標,請使用前一個目標的名稱定義變數,並將該變數用於後一個目標的 name 屬性和 deps。

這會明確連結兩個目標,尤其是在複雜的情況下,如果有多個目標名稱是根據其他目標名稱而定,就更容易醒目顯示和搜尋。

除非能提高可讀性 (例如所有目標名稱都定義在同一處),否則請勿將變數用於內部未使用的目標。

包裝內建和常見規則、巨集和函式

在 Fuchsia 平台程式碼集 中編寫巨集,以取代常見的 Bazel 規則、巨集或函式時,請在包裝的名稱加上 fx_ 前置字元。例如,請使用 fx_cc_library(),而非 cc_library()。 「常見」包括 Bazel 內建的符號 (包括 native.*),以及常見存放區 (例如 rules_cc) 中的符號。此外,如果發生其他衝突 (例如與 package 無關的 fx_package()),也請使用這個前置字元。請勿使用 fuchsia_ 前置字元,因為 fuchsia_... 檔案和符號位於 Fuchsia Bazel SDK。

避免快取或遠端處理大型構件

請參閱「避免大型構件的快取」。