このページでは、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 では、シングルトンとの比較は is
で行うことが推奨されていますが、これは Starlark の演算子ではありません。
Docstring
docstring を使用して、ファイルと関数を文書化します。各 .bzl
ファイルの先頭に docstring を使用し、各パブリック関数に docstring を使用します。
ルールとアスペクトを文書化する
ルールとアスペクト、それらの属性、プロバイダとそのフィールドは、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()
のすべての使用が 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
など)と同じ目的で使用される場合は、属性と同じように名前を付けます(下記を参照)。 - マクロを呼び出すときは、キーワード引数のみを使用します。これはルールと一貫性があり、読みやすさが大幅に向上します。
エンジニアは、関連するルールの Starlark API が特定のユースケースに十分でない場合、ルールがネイティブ コードの Bazel 内で定義されているか、Starlark で定義されているかにかかわらず、マクロを作成することがよくあります。この問題が発生した場合は、ルール作成者に 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
という名前を付けることです。 - 明確に定義されたプロバイダ インターフェースを使用して、ルール間で情報を渡します。プロバイダ フィールドを宣言して文書化します。
- 拡張性を考慮してルールを設計します。他のルールがルールとやり取りし、プロバイダにアクセスして、作成したアクションを再利用する可能性があることを考慮してください。
- ルールでパフォーマンス ガイドラインに従います。