このページでは、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
ファイルの先頭の 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()
関数を使用しないでください。デバッグ専用であり、.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
は、マクロで定義されたターゲットの名前を導き出すためにのみ使用し、他の目的には使用しないでください。たとえば、マクロ自体では生成されない依存関係や入力ファイルを派生させるための名前を使用しないでください。- マクロで作成したターゲットはすべて、なんらかの方法でメイン ターゲットに結合する必要があります。
- マクロ内のパラメータ名には一貫性を持たせます。パラメータがメイン ターゲットに属性値として渡される場合、その名前は同じにします。マクロ パラメータが共通のルール属性(
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
: コンパイルに不要なランタイム依存関係。
- 不明瞭な動作をする属性(特別な置換を含む文字列テンプレート、特定の要件で呼び出されるツールなど)の場合は、属性の宣言に
doc
キーワード引数(attr.label_list()
など)を使用してドキュメントを提供します。 - ルールの実装関数は、ほとんどの場合、プライベート関数である必要があります(先頭にアンダースコアが付いています)。一般的なスタイルは、
myrule
の実装関数に_myrule_impl
という名前を付けます。 - 明確に定義された provider インターフェースを使用して、ルール間で情報を渡します。プロバイダ フィールドを宣言し、文書化します。
- 拡張性を考慮してルールを設計します。ルールの操作、プロバイダへのアクセス、作成したアクションの再利用が必要になることもあります。
- ルールのパフォーマンス ガイドラインを遵守します。