.bzl 樣式指南

回報問題 查看原始碼

本頁面說明 Starlark 的基本樣式規範,也包含巨集和規則的相關資訊。

Starlark 是一種語言,用於定義軟體的建構方式,因此既是程式設計,也是程式設計語言的一種。

您將使用 Starlark 撰寫 BUILD 檔案、巨集和建置規則。巨集和規則基本上是中繼語言,用於定義 BUILD 檔案的寫入方式。BUILD 檔案旨在保持簡單明瞭。

所有軟體的讀取頻率都高於寫入值。對 Starlark 來說,這一點尤其重要,因為工程師會讀取 BUILD 檔案來瞭解目標的依附元件,以及建構作業的詳細資料。這項讀取作業通常在傳送、趕時間或完成其他工作時進行。因此,簡易性和可讀性很重要,讓使用者能夠快速剖析和理解 BUILD 檔案。

當使用者開啟 BUILD 檔案時,他們想要快速瞭解檔案中的目標清單,或是查看該 C++ 程式庫的來源清單;或者從該 Java 二進位檔中移除依附元件。每次新增抽象層時,都會讓使用者難以完成這些工作。

BUILD 檔案也由多種不同的工具加以分析和更新。如果工具使用抽象,您的 BUILD 檔案可能無法修改。讓 BUILD 檔案保持精簡,以便取得更優質的工具。隨著程式碼集的發展,越來越多的 BUILD 檔案會頻繁更新,以更新程式庫或清除。

通用建議

建立風格

Python 樣式

如有疑慮,請盡可能遵循 PEP 8 樣式指南。請特別注意,為了按照 Python 慣例,使用四個空格而不是兩個空格。

由於 Starlark 不是 Python,因此 Python 樣式的某些部分不適用。例如,PEP 8 建議使用 is 來比較單例模式與單例模式的比較,而不是在 Starlark 中的運算子。

文件字串

使用 docstrings 記錄文件與函式。 在每個 .bzl 檔案的頂端使用 docstring,並為每個公用函式使用 docstring。

文件規則和各方面

請使用 doc 引數記錄規則、元件及其屬性、提供者及其欄位。

命名慣例

  • 變數和函式名稱使用小寫,並加上底線 ([a-z][a-z0-9_]*) 分隔,例如 cc_library
  • 頂層私人值的開頭為一個底線。Bazel 規定,其他檔案無法使用私人值。本機變數不應使用底線前置字串。

文行長度

BUILD 檔案一樣,由於標籤長度可能較長,因此程式碼不會有嚴格限制。 如果可以的話,請嘗試每行使用最多 79 個字元 (按照 Python 的樣式指南 PEP 8)。這項規範不應嚴格執行:編輯者應顯示超過 80 欄、自動化變更經常會引入較長的行數,而人類也不應將已可讀的行花費在可讀的行上。

關鍵字引數

在關鍵字引數中,建議使用等號前後的空格:

def fct(name, srcs):
    filtered_srcs = my_filter(source = srcs)
    native.cc_library(
        name = name,
        srcs = filtered_srcs,
        testonly = True,
    )

布林值

偏好值 (例如在規則中使用布林值屬性) 時,最好使用 TrueFalse 的值 (而非 10)。

請勿在實際工作環境程式碼中使用 print() 函式,因為這個函式只能用於偵錯,而且會將 .bzl 檔案的所有直接和間接使用者視為垃圾內容。唯一的例外是,您可以提交使用 print() 的當程式碼預設為停用的程式碼,而且只能透過編輯來源來啟用。舉例來說,如果 print() 的所有用途都受到 if DEBUG: 的保護,其中 DEBUG 的硬式編碼為 False。請謹記這些陳述式是否實用,可說明對可讀性的影響。

巨集

巨集是一種在載入階段將一或多個規則執行個體化的函式。一般來說,請盡可能使用規則而非巨集。使用者看到的建構圖表與 Bazel 在建構期間使用的建構圖不同,巨集會在 Bazel 執行任何建構圖分析之前展開。

因此,如果發生問題,使用者必須瞭解巨集的實作,以排解建構問題。此外,bazel query 結果可能難以解讀,因為結果中顯示的目標均來自巨集展開。最後,各方面並不知道巨集,因此根據不同層面 (IDE 和其他元件) 進行的工具可能會失敗。

巨集的一種安全用途,就是定義其他用途,也就是直接在 Bazel CLI 或 BUILD 檔案中參照其他目標:在這種情況下,只有這些目標的使用者需要知道這些元素,而巨集產生的任何建構問題絕不會超出其使用量。

對於定義已產生目標的巨集 (不應在 CLI 中引用的巨集實作詳細資料,或取決於未由該巨集執行個體化的巨集),請採用下列最佳做法:

  • 巨集應採用 name 引數,並以該名稱定義目標。該目標會成為該巨集的主要目標
  • 產生的目標 (即巨集定義的所有其他目標),應:
    • 然後名稱前加上 <name>_<name>。例如,使用 name = '%s_bar' % (name)
    • 瀏覽權限受限 (//visibility:private)
    • 擁有 manual 標記,以避免擴充萬用字元目標 (:all...:* 等)。
  • name 只能用來產生巨集定義的目標名稱,不能用於其他用途。例如,請勿使用名稱產生由巨集本身產生的依附元件或輸入檔案。
  • 巨集中建立的所有目標應以某種方式耦合至主要目標。
  • 讓巨集中的參數名稱保持一致。如果參數做為屬性值傳遞至主要目標,名稱則維持不變。如果巨集參數的用途與一般規則屬性 (例如 deps) 相同,請像這個屬性一樣命名名稱 (請參閱下方說明)。
  • 呼叫巨集時,只能使用關鍵字引數。這與規則一致,可以大幅提高可讀性。

當相關規則的 Starlark API 不足以用於特定用途時,工程師通常會編寫巨集,無論規則是在原生程式碼中的 Bazel 中定義,還是在 Starlark 中定義皆然。如果您遇到這個問題,請詢問規則作者,他們是否可以擴充 API 來達成目標。

原則上,巨集越接近規則就越好。

另請參閱巨集

規則

  • 規則、層面及其屬性應使用小寫者名稱 (「英文案例」)。
  • 規則名稱可用來從規則的相依性 (或使用者為分葉規則) 的角度說明規則產生的主要構件。這不一定是檔案尾碼。例如,用來產生 C++ 構件的規則,可用來當做 Python 擴充功能,稱為 py_extension。大部分語言的一般規則包括:
    • *_library - 編譯單位或「模組」。
    • *_binary:可產生執行檔或部署單元的目標。
    • *_test:測試目標。可包含多個測試。預期 *_test 目標中的所有測試都使用相同的主題 (例如測試單一程式庫)。
    • *_import:封裝預先編譯成果的目標,例如 .jar,或在編譯期間使用的 .dll
  • 請為屬性使用一致的名稱和類型。部分適用的屬性包括:
    • srcslabel_list,允許檔案:來源檔案,通常為人為作者。
    • depslabel_list,通常允許檔案:編譯依附元件。
    • datalabel_list,允許檔案:資料檔案,例如測試資料等。
    • runtime_depslabel_list:編譯時不需要的執行階段依附元件。
  • 針對任何不明顯行為的屬性 (例如含有特殊替代字串的字串範本,或是有特定要求叫用的工具),請使用屬性的 doc 關鍵字引數提供說明文件 (attr.label_list() 或類似內容)。
  • 規則實作函式幾乎一律都是私人函式 (名稱開頭是底線)。常見的樣式為 myrule 實作實作函式,名稱為 _myrule_impl
  • 使用定義完善的 provider 介面,在規則之間傳遞資訊。宣告和文件提供者欄位。
  • 因此,設計規則時應將擴展能力納入考量。假設有其他規則可能會與您的規則互動、存取提供者,並重複使用您建立的動作。
  • 請在規則中遵守成效指南