建構樣式指南

回報問題 查看來源 Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

BUILD 檔案格式設定與 Go 相同,標準化工具會處理大部分的格式設定問題。Buildifier 是一種工具,可剖析原始碼並以標準樣式發出。因此,每個 BUILD 檔案都會以相同的方式自動格式化,在程式碼審查期間不會發生格式問題。此外,工具也能更輕鬆地瞭解、編輯及產生 BUILD 檔案。

BUILD 檔案格式必須與 buildifier 的輸出內容相符。

格式範例

# Test code implementing the Foo controller.
package(default_testonly = True)

py_test(
    name = "foo_test",
    srcs = glob(["*.py"]),
    data = [
        "//data/production/foo:startfoo",
        "//foo",
        "//third_party/java/jdk:jdk-k8",
    ],
    flaky = True,
    deps = [
        ":check_bar_lib",
        ":foo_data_check",
        ":pick_foo_port",
        "//pyglib",
        "//testing/pybase",
    ],
)

檔案結構

建議:使用下列順序 (每個元素都是選用):

  • 套件說明 (註解)

  • 所有load()對帳單

  • package() 函式。

  • 規則和巨集的呼叫

Buildifier 會區分獨立註解和附加至元素的註解。如果註解未附加至特定元素,請在註解後使用空白行。進行自動化變更時 (例如刪除規則時保留或移除留言),這項區別非常重要。

# Standalone comment (such as to make a section in a file)

# Comment for the cc_library below
cc_library(name = "cc")

目前套件中目標的參照

檔案應以相對於套件目錄的路徑參照 (切勿使用向上參照,例如 ..)。產生的檔案應加上「:」前置字串,表示這些檔案並非來源。來源檔案不得以 : 為前置字串。規則應以 : 為前置字串。舉例來說,假設 x.cc 是來源檔案:

cc_library(
    name = "lib",
    srcs = ["x.cc"],
    hdrs = [":gen_header"],
)

genrule(
    name = "gen_header",
    srcs = [],
    outs = ["x.h"],
    cmd = "echo 'int x();' > $@",
)

目標命名

目標名稱應具描述性,如果目標包含一個來源檔案,目標名稱通常應衍生自該來源 (例如,chat.cccc_library 可命名為 chat,或 DirectMessage.javajava_library 可命名為 direct_message)。

套件的同名目標 (與所含目錄同名的目標) 應提供目錄名稱所述的功能。如果沒有這類目標,請勿建立同名目標。

參照同名目標時,請盡量使用簡短名稱 (//x,而非 //x:x)。如果您位於相同套件中,請盡量使用本機參照 (:x,而非 //x)。

請避免使用具有特殊意義的「保留」目標名稱。包括 all__pkg____subpackages__,這些名稱具有特殊語意,使用時可能會造成混淆和非預期行為。

如果沒有通用的團隊慣例,以下是 Google 廣泛使用的部分非約束性建議:

  • 一般來說,請使用「snake_case」
    • 如果 java_library 只有一個 src,表示使用的名稱與不含副檔名的檔案名稱不同
    • 如果是 Java *_binary*_test 規則,請使用「Upper CamelCase」。這樣一來,目標名稱就能與其中一個 src 相符。對於 java_test,這可讓 test_class 屬性從目標名稱推斷而來。
  • 如果特定目標有多個變體,請新增後置字元來消除歧義 (例如 :foo_dev:foo_prod:bar_x86:bar_x64)
  • _test_unittestTestTests 為目標的後置字串 _test
  • 避免使用無意義的後置字元,例如 _lib_library (除非為避免 _library 目標與對應的 _binary 發生衝突,否則請勿使用)
  • 適用於 proto 相關目標:
    • proto_library 目標的名稱結尾應為 _proto
    • 特定語言的 *_proto_library 規則應與基礎原型相符,但要將 _proto 替換為特定語言的後置字串,例如:
      • cc_proto_library_cc_proto
      • java_proto_library_java_proto
      • java_lite_proto_library_java_proto_lite

顯示設定

可見度應盡可能縮小範圍,同時仍允許測試和反向依附元件存取。視情況使用 __pkg____subpackages__

避免將套件 default_visibility 設為 //visibility:public//visibility:public 只能針對專案公開 API 中的目標個別設定。這些可能是專為外部專案依附而設計的程式庫,或是可供外部專案建構程序使用的二進位檔。

依附元件

依附元件應僅限於直接依附元件 (規則中列出的來源所需依附元件)。請勿列出遞移依附元件。

套件本機的依附元件應列在最前面,並以與上方「參照目前套件中的目標」一節相容的方式參照 (而非使用絕對套件名稱)。

建議直接列出依附元件,做為單一清單。將多個目標的「通用」依附元件放入變數中,會降低可維護性,導致工具無法變更目標的依附元件,並可能導致未使用的依附元件。

Globs

使用 [] 表示「沒有目標」。請勿使用不相符的 glob,因為這比空白清單更容易出錯,也較不明顯。

遞迴

請勿使用遞迴 glob 來比對來源檔案 (例如 glob(["**/*.java"]))。

遞迴 glob 會略過含有 BUILD 檔案的子目錄,因此難以推斷 BUILD 檔案。

一般來說,遞迴 glob 的效率不如每個目錄都有 BUILD 檔案,且檔案之間定義了依附元件圖表,因為這樣可提升遠端快取和並行處理的效率。

建議您在每個目錄中撰寫 BUILD 檔案,並定義目錄之間的依附元件關係圖。

非遞迴

一般來說,非遞迴的 glob 都可以接受。

其他慣例

  • 使用大寫和底線宣告常數 (例如 GLOBAL_CONSTANT),使用小寫和底線宣告變數 (例如 my_variable)。

  • 即使標籤長度超過 79 個字元,也不應分割。 標籤應盡可能為字串常值。理由:方便尋找及取代。同時提升可讀性。

  • 名稱屬性的值應為常數字串 (巨集除外)。理由:外部工具會使用名稱屬性參照規則。他們需要找出規則,而不必解讀程式碼。

  • 設定布林值類型的屬性時,請使用布林值,而非整數值。 基於舊版原因,規則仍會視需要將整數轉換為布林值,但我們不建議這麼做。理由flaky = 1 可能會誤解為「重新執行一次,即可解決這個目標的問題」。flaky = True明確指出「這項測試不穩定」。

與 Python 樣式指南的差異

雖然目標是與 Python 樣式指南相容,但仍有幾項差異:

  • 沒有嚴格的行長度限制。長註解和長字串通常會分割成 79 欄,但這並非必要。不應在程式碼審查或預先提交指令碼中強制執行。原因:標籤可能會很長,超過這個限制。工具通常會產生或編輯 BUILD 檔案,這與行長度限制不相容。

  • 系統不支援隱含字串串連。使用 + 運算子。 理由BUILD 檔案包含許多字串清單。很容易忘記逗號,導致結果完全不同。這在過去造成許多錯誤。另請參閱這項討論。

  • 在規則中,關鍵字引數的 = 符號前後要加上空格。理由:具名引數比 Python 更常使用,且一律位於獨立一行。空格可提升可讀性。這項慣例已存在很長一段時間,不值得修改所有現有的 BUILD 檔案。

  • 根據預設,字串會使用雙引號。理由:Python 樣式指南未指定此項目,但建議保持一致。因此我們決定只使用雙引號字串。許多語言會使用雙引號標註字串常值。

  • 在兩個頂層定義之間使用單一空白行。理由BUILD 檔案的結構與一般 Python 檔案不同。當中只包含頂層陳述式。使用單一空白行可縮短 BUILD 檔案。