Build スタイルガイド

BUILD のファイル形式は Go と同じアプローチに従います。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() 関数。

  • ルールとマクロの呼び出し

ビルド機能では、単独のコメントと、要素に添付されたコメントが区別されます。特定の要素にコメントを添付しない場合は、コメントの後に空行を使用します。この区別は、自動変更を行う場合(ルールを削除するときにコメントを保持または削除する場合など)、重要です。

# 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();' > $@",
)

ターゲットの命名

ターゲット名はわかりやすいものにする必要があります。ターゲットにソースファイルが 1 つ含まれる場合、ターゲットは通常、そのソースから派生した名前になります(たとえば、chat.cccc_library の名前は chat に、DirectMessage.javajava_library の名前は direct_message とします)。

パッケージの名前付きターゲット(含まれているディレクトリと同じ名前のターゲット)は、ディレクトリ名で記述された機能を提供する必要があります。そのようなターゲットがない場合は、同名ターゲットを作成しないでください。

同名ターゲットを参照する場合は、略称を使用します(//x:x ではなく //x)。同じパッケージ内の場合は、ローカル参照(//x ではなく :x)を使用します。

特別な意味を持つ「予約済み」のターゲット名は使用しないでください。これには all__pkg____subpackages__ が含まれます。これらの名前には特別なセマンティクスがあり、これらを使用すると混乱や予期しない動作が発生する可能性があります。

以下は、Google で広く使用されている、拘束力のない推奨事項です。チーム間で広く浸透している慣習はありません。

  • 通常は "snake_case" を使用します。
    • src が 1 つの java_library の場合、拡張子のないファイル名とは異なる名前を使用します。
    • Java の *_binary ルールと *_test ルールの場合は、Upper CamelCase を使用します。これにより、ターゲット名を src のいずれかと一致させることができます。java_test では、これによりターゲットの名前から test_class 属性を推測できます。
  • 特定のターゲットに複数のバリアントがある場合は、曖昧さを取り除くためにサフィックスを追加します(:foo_dev:foo_prod、または :bar_x86:bar_x64
  • _test ターゲットに _test_unittestTest、または Tests を付加する
  • _lib_library などの無意味な接尾辞は使用しないでください(_library ターゲットとそれに対応する _binary との競合を回避する必要がある場合を除く)。
  • proto 関連のターゲットの場合:
    • proto_library ターゲットの名前は _proto で終わる必要があります。
    • 言語固有の *_proto_library ルールは基となる proto と一致する必要がありますが、_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 内のターゲットに対してのみ個別に設定する必要があります。外部プロジェクトや、外部プロジェクトのビルドプロセスで使用されるバイナリに依存するように設計されたライブラリなどがこれに該当します。

依存関係

依存関係は、直接的な依存関係(ルールにリストされているソースが必要とする依存関係)に限定する必要があります。推移的依存関係は列挙しないでください。

パッケージ ローカル依存関係を最初にリストし、上記の現在のパッケージ内のターゲットへの参照セクションと互換性のある方法で参照する必要があります(絶対パッケージ名ではありません)。

単一のリストとして、依存関係を直接リストすることをおすすめします。複数のターゲットの「共通」依存関係を変数に入れると、保守性が低下し、ツールによるターゲットの依存関係の変更が不可能になり、未使用の依存関係が発生する可能性があります。

glob

[] で「ターゲットなし」を指定します。何もマッチしない glob は使用しないでください。空のリストよりもミスが生じやすく、わかりにくくなります。

再帰

ソースファイルの照合に再帰 glob を使用しないでください(例: glob(["**/*.java"]))。

再帰 glob を使用すると、BUILD ファイルを含むサブディレクトリがスキップされるため、BUILD ファイルの判断が難しくなります。

再帰 glob を使用すると、リモート キャッシュと並列処理が改善されるため、一般的に、ディレクトリごとに BUILD ファイルを使用して依存関係グラフを定義する場合よりも効率が悪くなります。

各ディレクトリに BUILD ファイルを作成し、ディレクトリ間の依存関係グラフを定義することをおすすめします。

非再帰的

非再帰 glob であれば、一般的には許容されます。

その他の規則

  • 定数(GLOBAL_CONSTANT など)の宣言には大文字とアンダースコアを使用し、変数(my_variable など)の宣言には小文字とアンダースコアを使用します。

  • ラベルは 79 文字を超えても分割しないでください。ラベルは可能な限り、文字列リテラルにする必要があります。理由: 検索と置換が簡単になります。また、読みやすさも向上します。

  • name 属性の値はリテラル定数文字列にする必要があります(マクロの場合を除く)。理由: 外部ツールは name 属性を使用してルールを参照しています。コードを解釈せずにルールを見つける必要があります。

  • ブール値型の属性を設定する場合は、整数値ではなくブール値を使用します。従来の理由から、ルールで必要に応じて整数がブール値に変換されますが、これは推奨されません。根拠: flaky = 1 は、「1 回再実行することでこのターゲットをデフレークする」と誤認する可能性があります。flaky = True は「このテストは不安定です」と一言で言います。

Python スタイルガイドとの違い

Python スタイルガイドとの互換性が目標ですが、いくつかの違いがあります。

  • 行の長さに厳格な制限はありません。長いコメントと長い文字列は 79 列に分割されることがよくありますが、必須ではありません。コードレビューや presubmit スクリプトには適用しないでください。根拠: ラベルは長く、この上限を超えることがあります。ツールによって BUILD ファイルが生成または編集されることはよくありますが、行長の制限には適していません。

  • 暗黙的な文字列連結はサポートされていません。+ 演算子を使用します。理由: BUILD ファイルには多数の文字列リストが含まれています。カンマを忘れてしまいがちですが、その結果がまったく異なる結果になってしまいます。これにより、過去に多くのバグが生じてきました。こちらもご覧ください。

  • ルール内のキーワード引数には、= 記号の前後にスペースを使用します。根拠: 名前付き引数は Python の場合よりも頻繁に使用されています。また、常に別の行にあります。スペースを使うと読みやすさが向上します。この規則は長い間存在していたため、既存の BUILD ファイルをすべて変更することには価値がありません。

  • デフォルトでは、文字列には二重引用符を使用します。根拠: これは Python スタイルガイドでは指定されていませんが、一貫性を保つことを推奨しています。そのため、二重引用符で囲まれた文字列のみを使用することにしました。多くの言語では、文字列リテラルに二重引用符を使用します。

  • 2 つのトップレベル定義の間に 1 つの空白行を挿入します。根拠: BUILD ファイルの構造は、一般的な Python ファイルとは異なります。トップレベルのステートメントのみです。空白行を 1 行使用すると、BUILD ファイルが短くなります。