建構樣式指南

BUILD 檔案格式與 Go 相同,而標準化工具會處理大部分的格式問題。建構工具是一項工具,可剖析及發出標準樣式的原始碼。因此,每個 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() 函式。

  • 對規則和巨集的呼叫

建構工具會區分獨立註解和元素附加的註解。如果註解並未附加至特定元素,請在該元素後方使用空白行。區別在執行自動化變更時非常重要 (例如,在刪除規則時保留或移除註解)。

# 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"
    • 對於具有 srcjava_library,這表示使用的名稱與沒有副檔名的檔案名稱不同。
    • 如果是 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 檔案,並定義檔案之間的依附元件圖表。

非遞迴

一般而言,可接受非遞迴的斑點。

其他慣例

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

  • 即便超過 79 個字元,也不應分割標籤。標籤應盡可能包含字串常值。原因:您就能輕鬆尋找與取代物件。改善可讀性。

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

  • 設定布林類型屬性時,請使用布林值,而非整數值。就舊版而言,規則仍會視需要將整數轉換為布林值,但我們不建議這麼做。理由flaky = 1 可能會寫錯為「藉由重新執行一次這個目標來防禦這個目標」。flaky = True 會明確表示「這項測試不穩定」。

與 Python 樣式指南的差異

雖然目標是與 Python 樣式指南的相容性,但還是有幾點差異:

  • 沒有嚴格的行長度限制。長註解和長字串通常會分割為 79 個資料欄,但並非必要。因此請勿在程式碼審查或預先提交指令碼中強制執行。理由:標籤可以過長,超過此限制。BUILD 檔案常由工具產生或編輯,這種工具不會超出行長度限制。

  • 不支援隱式字串串連。使用 + 運算子。理由BUILD 檔案包含許多字串清單。使用者很容易忘記一個逗號,因此會產生完全不同的結果。這在過去產生了許多錯誤另請參閱此討論。

  • 請在規則中的 = 符號前後加上空格。理由:已命名的引數比 Python 頻率高,而且一律以單獨行顯示。聊天室可提高可讀性。此慣例長期以來行之有年,不值得修改所有現有的 BUILD 檔案。

  • 根據預設,字串會使用雙引號。理由:這未在 Python 樣式指南中指定,但建議的一致性。因此,我們決定僅使用雙引號的字串。許多語言會在字串常值中使用雙引號。

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