このページでは、Starlark の基本的なスタイル ガイドラインについて説明します。また、マクロとルールについても説明します。
Starlark は、ソフトウェアのビルド方法を定義する言語であり、プログラミング言語と構成言語の両方です。
Starlark を使用して、BUILD
ファイル、マクロ、ビルドルールを記述します。マクロとルールは基本的にメタ言語であり、BUILD
ファイルの作成方法を定義します。BUILD
ファイルはシンプルで反復的なファイルです。
すべてのソフトウェアは、書き込まれるよりも多くの回数で読み取られます。これは Starlark の場合に特に当てはまります。エンジニアは BUILD
ファイルを読み取って、ターゲットの依存関係とビルドの詳細を把握します。このような読み取りは、ついでに、急いで、または他のタスクの実行と並行して行われることがよくあります。そのため、ユーザーが BUILD
ファイルをすばやく解析して理解できるようにするには、シンプルさと読みやすさが非常に重要です。
ユーザーが BUILD
ファイルを開いたときに、そのファイル内のターゲットのリストをすばやく確認したり、その C++ ライブラリのソースのリストを表示したり、その Java バイナリから依存関係を削除したりできます。抽象化レイヤを追加するたびに、ユーザーがこれらのタスクを行うことが困難になります。
BUILD
ファイルもさまざまなツールで分析、更新されます。抽象化を使用している場合、ツールで BUILD
ファイルを編集できないことがあります。BUILD
ファイルをシンプルに保つことで、より優れたツールを利用できます。コードベースが大きくなるにつれて、ライブラリの更新やクリーンアップを行うために、多数の BUILD
ファイルにわたって変更を行う頻度が高くなります。
一般的なアドバイス
- 書式設定ツールとリンタとして Buildifier を使用します。
- テストに関するガイドラインに従います。
スタイル
Python スタイル
不明な点がある場合は、可能な限り PEP 8 スタイルガイドに従ってください。特に、Python の規則に従って、インデントに 2 つのスペースではなく 4 つのスペースを使用します。
Starlark は Python ではないため、Python スタイルのいくつかの側面は適用されません。たとえば PEP 8 では、Starlark の演算子ではない is
を使用してシングルトンと比較することが推奨されています。
docstring
docstring を使用してファイルと関数を記述します。各 .bzl
ファイルの上部にドキュメント コメントを使用し、公開関数ごとにドキュメント コメントを使用します。
ルールとアスペクトを文書化する
ルールとアスペクト、その属性、プロバイダとそのフィールドは、doc
引数を使用してドキュメント化する必要があります。
命名規則
- 変数名と関数名は小文字で、単語はアンダースコア(
[a-z][a-z0-9_]*
)で区切ります(cc_library
など)。 - 非公開のトップレベルの値は 1 つのアンダースコアで始まります。Bazel では、他のファイルからプライベート値を使用できないようにします。ローカル変数にアンダースコア接頭辞を使用しないでください。
行の長さ
BUILD
ファイルと同様に、ラベルは長くなる可能性があるため、厳密な行の長さの制限はありません。可能であれば、1 行あたり 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,
)
ブール値
ブール値には、1
や 0
ではなく、True
と False
の値を使用する(ルールでブール属性を使用する場合など)。
print はデバッグにのみ使用する
本番環境のコードでは print()
関数を使用しないでください。この関数はデバッグ専用であり、.bzl
ファイルの直接的および間接的なすべてのユーザーにスパム行為を生じさせます。唯一の例外は、print()
がデフォルトで無効になっており、ソースの編集によってのみ有効にできる場合に、print()
を使用するコードを送信できることです。たとえば、print()
のすべての使用が if DEBUG:
でガードされ、DEBUG
が False
にハードコードされている場合などです。これらの記述が、読みやすさへの影響を正当化するほど有用かどうかに注意してください。
マクロ
マクロは、読み込みフェーズで 1 つ以上のルールをインスタンス化する関数です。一般的に、可能な限りマクロではなくルールを使用します。ユーザーが確認できるビルドグラフは、ビルド中に Bazel が使用するビルドグラフとは異なります。マクロは、Bazel がビルドグラフの分析を行う前に展開されます。
そのため、問題が発生した場合、ユーザーはマクロの実装を理解してビルドの問題をトラブルシューティングする必要があります。また、結果に表示されるターゲットはマクロ展開から取得されるため、bazel
query
の結果を解釈するのは難しい場合があります。最後に、アスペクトはマクロを認識しないため、アスペクトに依存するツール(IDE など)が失敗する可能性があります。
マクロを安全に使用するには、Bazel CLI または BUILD ファイルで直接参照することを目的とした追加のターゲットを定義します。その場合、それらのターゲットのエンドユーザーのみがそれらについて知る必要があり、マクロによって発生するビルドの問題は、その使用から遠く離れることはありません。
生成されたターゲット(CLI で参照されることを想定していない、またはそのマクロによってインスタンス化されないターゲットによって依存することを想定していないマクロの実装の詳細)を定義するマクロについては、次のベスト プラクティスに従ってください。
- マクロは
name
引数を取り、その名前のターゲットを定義する必要があります。そのターゲットがそのマクロのメイン ターゲットになります。 - 生成されたターゲット(マクロで定義された他のすべてのターゲット)は、次の要件を満たす必要があります。
- 名前の前に
<name>
または_<name>
が付いています。たとえば、name = '%s_bar' % (name)
を使用します。 - 公開が制限されている(
//visibility:private
) - ワイルドカード ターゲット(
:all
、...
、:*
など)の拡張を回避するためにmanual
タグがある。
- 名前の前に
name
は、マクロで定義されたターゲットの名前を導出する場合にのみ使用し、それ以外には使用しないでください。たとえば、マクロ自体によって生成されていない依存関係や入力ファイルを名前を使用して導出しないでください。- マクロ内で作成されたすべてのターゲットは、なんらかの方法でメイン ターゲットに結合する必要があります。
- 通常、マクロを定義する場合は
name
を最初の引数にする必要があります。 - マクロ内のパラメータ名は一貫したものにしてください。パラメータを属性値としてメイン ターゲットに渡す場合は、名前を同じにします。マクロ パラメータが共通のルール属性(
deps
など)と同じ目的を果たす場合は、属性と同じ名前を指定します(下記参照)。 - マクロを呼び出すときは、キーワード引数のみを使用します。これはルールに準拠しており、読みやすさが大幅に向上します。
エンジニアは、ルールがネイティブ コードの Bazel 内で定義されているか、Starlark 内で定義されているかにかかわらず、関連するルールの Starlark API が特定のユースケースに対して不十分な場合に、マクロを作成することがよくあります。この問題が発生した場合は、目標を達成するために API を拡張できるかどうか、ルールの作成者に問い合わせてください。
経験則では、ルールに近いマクロが多いほど、より良い結果が得られます。
マクロもご覧ください。
ルール
- ルール、アスペクト、およびそれらの属性には、小文字の名前(「スネークケース」)を使用する必要があります。
- ルール名は、依存関係(またはリーフルールの場合はユーザー)の観点から、ルールによって生成される主なアーティファクトの種類を説明する名詞です。これは、必ずしもファイルの接尾辞ではありません。たとえば、Python 拡張機能として使用することを目的とした C++ アーティファクトを生成するルールは
py_extension
という名前にします。ほとんどの言語では、一般的なルールは次のとおりです。*_library
- コンパイル単位または「モジュール」。*_binary
- 実行可能ファイルまたはデプロイ ユニットを生成するターゲット。*_test
- テスト ターゲット。複数のテストを含めることができます。*_test
ターゲット内のすべてのテストが同じテーマのバリエーションであることを想定します(単一のライブラリのテストなど)。*_import
: 事前コンパイル済みアーティファクト(.jar
など)またはコンパイル時に使用される.dll
をカプセル化するターゲット。
- 属性の名前と型に一貫性を持たせます。一般に適用される属性には次のようなものがあります。
srcs
:label_list
。ファイル(通常は人間が作成したソースファイル)を許可します。deps
:label_list
。通常、ファイル: コンパイル依存関係を許可しません。data
:label_list
。許可されるファイル: データファイル(テストデータなど)。runtime_deps
:label_list
: コンパイルに必要ないランタイム依存関係。
- 動作がわかりにくい属性(特別な置換を含む文字列テンプレートや、特定の要件で呼び出されるツールなど)については、属性の宣言(
attr.label_list()
など)にdoc
キーワード引数を使用してドキュメントを提供します。 - ルールの実装関数は、ほとんどの場合、プライベート関数(先頭にアンダースコアが付いた名前)にする必要があります。
myrule
の実装関数に_myrule_impl
という名前を付けるのが一般的なスタイルです。 - 明確に定義されたプロバイダ インターフェースを使用して、ルール間で情報を渡します。プロバイダ フィールドを宣言してドキュメント化します。
- 拡張性を考慮してルールを設計します。他のルールがルールとやり取りしたり、プロバイダにアクセスしたり、作成したアクションを再利用したりする可能性があることを考慮してください。
- ルールのパフォーマンス ガイドラインに従います。