このページでは、マクロの基本的な使用方法について説明します。また、一般的なユースケース、デバッグ、規則についても説明します。
マクロは、ルールをインスタンス化できる BUILD
ファイルから呼び出される関数です。
マクロは、主にカプセル化や、既存のルールやその他のマクロのコードの再利用に使用されます。読み込みフェーズの終わりまでに、マクロは存在しなくなり、Bazel はインスタンス化されたルールの具体的なセットのみを認識します。
使用状況
マクロは通常、ルールを再利用したい場合に使用されます。
たとえば、BUILD
ファイルの genrule は、//:generator
を使用して some_arg
引数をコマンドにハードコードしたファイルを生成します。
genrule(
name = "file",
outs = ["file.txt"],
cmd = "$(location //:generator) some_arg > $@",
tools = ["//:generator"],
)
さまざまな引数を指定してより多くのファイルを生成したい場合は、このコードをマクロ関数に抽出することもできます。マクロ file_generator
を呼び出してみましょう。マクロには name
パラメータと arg
パラメータがあります。genrule を次のように置き換えます。
load("//path:generator.bzl", "file_generator")
file_generator(
name = "file",
arg = "some_arg",
)
file_generator(
name = "file-two",
arg = "some_arg_two",
)
file_generator(
name = "file-three",
arg = "some_arg_three",
)
ここでは、//path
パッケージにある .bzl
ファイルから file_generator
シンボルを読み込みます。マクロ関数の定義を別の .bzl
ファイルに含めることで、BUILD
ファイルをクリーンで宣言的な状態に保つことができます。.bzl
ファイルは、ワークスペース内のどのパッケージからでも読み込むことができます。
最後に、path/generator.bzl
で、元の genrule 定義をカプセル化してパラメータ化するマクロの定義を作成します。
def file_generator(name, arg, visibility=None):
native.genrule(
name = name,
outs = [name + ".txt"],
cmd = "$(location //:generator) %s > $@" % arg,
tools = ["//:generator"],
visibility = visibility,
)
マクロを使用してルールを連結することもできます。次の例は、連鎖 genrule を示しています。ここで、genrule は、前の genrule の出力を入力として使用します。
def chained_genrules(name, visibility=None):
native.genrule(
name = name + "-one",
outs = [name + ".one"],
cmd = "$(location :tool-one) $@",
tools = [":tool-one"],
visibility = ["//visibility:private"],
)
native.genrule(
name = name + "-two",
srcs = [name + ".one"],
outs = [name + ".two"],
cmd = "$(location :tool-two) $< $@",
tools = [":tool-two"],
visibility = visibility,
)
この例では、可視性の値を第 2 世代ルールにのみ割り当てています。これにより、マクロの作成者は、中間ルールの出力をワークスペース内の他のターゲットに依存しないようにできます。
マクロを展開する
マクロの動作を調査する際は、query
コマンドと --output=build
を使用して展開された形式を表示します。
$ bazel query --output=build :file
# /absolute/path/test/ext.bzl:42:3
genrule(
name = "file",
tools = ["//:generator"],
outs = ["//test:file.txt"],
cmd = "$(location //:generator) some_arg > $@",
)
ネイティブ ルールをインスタンス化する
ネイティブ ルール(load()
ステートメントを必要としないルール)は、native モジュールからインスタンス化できます。
def my_macro(name, visibility=None):
native.cc_library(
name = name,
srcs = ["main.cc"],
visibility = visibility,
)
パッケージ名を知る必要がある場合(たとえば、どの BUILD
がマクロを呼び出しているか)は、関数 native.package_name() を使用します。native
は .bzl
ファイル内でのみ使用できます。WORKSPACE
ファイルまたは BUILD
ファイル内では使用できません。
マクロでのラベルの解決
マクロは読み込みフェーズで評価されるため、マクロ内で発生する "//foo:bar"
などのラベル文字列は、マクロが定義されている .bzl
ファイルではなく、マクロが使用される BUILD
ファイルに対して解釈されます。この動作は、一般に、公開されている Starlark ルールセットの一部であるためなど、他のリポジトリで使用することを想定したマクロには適していません。
Starlark ルールと同じ動作を得るには、ラベル文字列を Label
コンストラクタでラップします。
# @my_ruleset//rules:defs.bzl
def my_cc_wrapper(name, deps = [], **kwargs):
native.cc_library(
name = name,
deps = deps + select({
# Due to the use of Label, this label is resolved within @my_ruleset,
# regardless of its site of use.
Label("//config:needs_foo"): [
# Due to the use of Label, this label will resolve to the correct target
# even if the canonical name of @dep_of_my_ruleset should be different
# in the main workspace, such as due to repo mappings.
Label("@dep_of_my_ruleset//tools:foo"),
],
"//conditions:default": [],
}),
**kwargs,
)
デバッグ
bazel query --output=build //my/path:all
には、評価後のBUILD
ファイルの外観が表示されます。すべてのマクロ、glob、ループが展開されます。既知の制限事項: 現在、select
式は出力に表示されません。ルールを生成した
generator_function
またはgenerator_name
(マクロの名前属性)bash $ bazel query --output=build 'attr(generator_function, my_macro, //my/path:all)'
に基づいて、出力をフィルタリングできます。ルール
foo
がBUILD
ファイル内のどこで生成されるかを確認するには、次の方法を試してください。BUILD
ファイルの先頭付近にcc_library(name = "foo")
という行を挿入します。Bazel を実行します。名前の競合のため、foo
ルールが作成されると例外が発生します。これにより、完全なスタック トレースが表示されます。デバッグには print を使用することもできます。読み込みフェーズ中は、メッセージが
DEBUG
ログ行として表示されます。まれなケースを除き、コードをprint
呼び出しに渡す前に削除するか、デフォルトでFalse
になるdebugging
パラメータで条件付きにします。
エラー
エラーをスローするには、fail 関数を使用します。問題と BUILD
ファイルの修正方法についてユーザーに明確に説明してください。エラーをキャッチすることはできません。
def my_macro(name, deps, visibility=None):
if len(deps) < 2:
fail("Expected at least two values in deps")
# ...
規則
ルールをインスタンス化するすべてのパブリック関数(アンダースコアで始まらない関数)には
name
引数が必要です。この引数はオプションにしないでください(デフォルト値を指定しないでください)。パブリック関数は、Python 規則に従って docstring を使用する必要があります。
BUILD
ファイルでは、マクロのname
引数は(位置引数ではなく)キーワード引数でなければなりません。マクロによって生成されたルールの
name
属性には、接頭辞として名前引数を含める必要があります。たとえば、macro(name = "foo")
とすると、cc_library
foo
と genrulefoo_gen
を生成できます。ほとんどの場合、オプションのパラメータには
None
のデフォルト値を設定します。None
はネイティブ ルールに直接渡すことができるため、引数を渡していない場合と同じように扱われます。そのため、0
、False
、[]
に置き換える必要はありません。デフォルトが複雑な場合や時間の経過とともに変化する可能性があるため、マクロは作成するルールに優先させる必要があります。また、明示的にデフォルト値に設定されるパラメータは、クエリ言語またはビルドシステムの内部を通じてアクセスされるときに設定されない(またはNone
に設定される)ものとは異なるように見えます。マクロにはオプションの
visibility
引数があります。