ルールは、Bazel で実行される一連のアクションを定義します。 出力のセットを生成するための入力です。この出力は、 ルールの ID によって返されるプロバイダ 実装関数。たとえば、C++ バイナリルールの例:
.cpp
ソースファイル(入力)のセットを取得します。- ソースファイルに対して
g++
を実行します(アクション)。 - 実行可能な出力とその他のファイルで
DefaultInfo
プロバイダを返す 実行時に利用できるようにします - 取得した C++ 固有の情報を使用して
CcInfo
プロバイダを返します。 その依存関係を定義します。
Bazel の観点からは、g++
と標準の C++ ライブラリも入力です
追加します。ルールライターは、ユーザーが指定するルールだけでなく、
ルールの実行に必要なツールとライブラリも
できます。
ルールを作成または変更する前に、Bazel の ビルドフェーズ。データ アナリストは、 (読み込み、分析、実行)。また、kubectl の マクロについて学び、ルールとルールの違いを理解する マクロ。使用を開始するには、まずルールのチュートリアルをご覧ください。 このページを参照用として使用します。
Bazel 自体には、いくつかのルールが組み込まれています。次のようなネイティブ ルールが
genrule
と filegroup
がコアサポートを提供します。
独自のルールを定義することで、言語とツールのサポートを追加できる
Bazel はネイティブではサポートしていません。
Bazel は、Terraform を使用してルールを作成するための拡張モデルを提供します。
Starlark 言語。これらのルールは、.bzl
ファイルに記述され、
BUILD
ファイルから直接読み込むことができます。
独自のルールを定義するときは、ルールでサポートする属性と、ルールで実行できる属性と 出力の生成方法を確認できます。
ルールの implementation
関数は、ルールの
分析フェーズ。この関数は
使用できます。代わりに、使用されるアクションを登録します。
ルールの出力をビルドし、必要に応じて
必要ありません。
ルールの作成
.bzl
ファイルで、rule 関数を使用して新しい
結果をグローバル変数に格納します。rule
の呼び出しでは、
属性と
実装関数:
example_library = rule(
implementation = _example_library_impl,
attrs = {
"deps": attr.label_list(),
...
},
)
これにより、example_library
という名前のルールの種類が定義されます。
また、rule
の呼び出しでは、ルールによってルールが
実行可能の出力(executable = True
を使用)、または
テスト実行可能ファイル(test = True
を使用)。ルールがテストルールの場合、
ルール名は _test
で終わる必要があります。
ターゲットのインスタンス化
ルールは、BUILD
ファイルで読み込んで呼び出すことができます。
load('//some/pkg:rules.bzl', 'example_library')
example_library(
name = "example_target",
deps = [":another_target"],
...
)
ビルドルールを呼び出しても値が返されませんが、 作成します。これをルールのインスタンス化と呼びます。これにより、サービス アカウントの名前が 新しいターゲットとターゲットの属性の値。
ルールは、Starlark 関数から呼び出し、.bzl
ファイルに読み込むこともできます。
ルールを呼び出す Starlark 関数は、Starlark マクロと呼ばれます。
Starlark のマクロは、最終的に BUILD
ファイルから呼び出す必要があります。
読み込みフェーズで BUILD
が呼び出されたとき
ターゲットをインスタンス化するために評価されます。
属性
属性はルールの引数です。属性は、エンティティに特定の値を ターゲットの implementation を参照するか、 依存関係のグラフを作成します。
ルール固有の属性(srcs
や deps
など)は、マップを渡すことで定義します。
属性名からスキーマ(attr
を使用して作成)に
モジュール)を rule
の attrs
パラメータに追加します。
一般的な属性:
name
と visibility
は、すべてのルールに暗黙的に追加されます。追加
各属性が暗黙的に追加され、
実行可能ルールとテストルールを具体的に指定します。属性
ルールに暗黙的に追加されているエントリは、渡すディクショナリに
attrs
。
依存関係属性
通常、ソースコードを処理するルールでは、 さまざまな種類の依存関係があります。
srcs
には、ターゲットのアクションで処理されるソースファイルを指定します。多くの場合、 属性スキーマは、並べ替えに必要なファイル拡張子を指定します ソースファイルを指定します。ヘッダー ファイルを使用する言語のルール 通常は、商品またはサービスによって処理されるヘッダーに、個別のhdrs
属性を 把握することですdeps
は、ターゲットのコード依存関係を指定します。属性スキーマは それらの依存関係が提供する必要があるプロバイダを指定します。( たとえば、cc_library
はCcInfo
を提供します)。data
は、実行時に任意の実行可能ファイルで使用できるようにするファイルを指定します。 これはターゲットによって異なりますこれにより、任意のファイルを あります。
example_library = rule(
implementation = _example_library_impl,
attrs = {
"srcs": attr.label_list(allow_files = [".example"]),
"hdrs": attr.label_list(allow_files = [".header"]),
"deps": attr.label_list(providers = [ExampleInfo]),
"data": attr.label_list(allow_files = True),
...
},
)
これらは依存関係属性の例です。次を指定する属性
入力ラベル(
attr.label_list
attr.label
、または
attr.label_keyed_string_dict
)
依存関係を指定するために
ターゲットと、そのラベル(または対応する
Label
個のオブジェクト)は、ターゲットが
定義します。これらのラベルのリポジトリ(場合によってはパス)が解決されます。
指定したターゲットを基準として移動されます。
example_library(
name = "my_target",
deps = [":other_target"],
)
example_library(
name = "other_target",
...
)
この例では、other_target
は my_target
の依存関係であるため、
other_target
が最初に分析されます。期間に周期がある場合はエラーになります。
ターゲットの依存関係グラフ。
非公開属性と暗黙的な依存関係
依存関係属性にデフォルト値を設定すると、暗黙的な依存関係が作成されます。これは、
ターゲット グラフの一部であるため、暗黙的に指定されます。
BUILD
ファイルで指定する。暗黙的な依存関係は、Terraform をハードコードする
ルールとツールの関係(例:
コンパイラ)を指定できます。ほとんどの場合、ユーザーは
使用されます。これはルールの実装関数内では
他の依存関係と同じです。
ユーザーに許可せずに暗黙的な依存関係を提供する場合
その値をオーバーライドするには、属性に名前を指定して private にできます
アンダースコア(_
)で始まる。非公開属性にはデフォルトの
使用できます。通常、暗黙的な属性ではプライベート属性を使用するのが適切です。
確認します。
example_library = rule(
implementation = _example_library_impl,
attrs = {
...
"_compiler": attr.label(
default = Label("//tools:example_compiler"),
allow_single_file = True,
executable = True,
cfg = "exec",
),
},
)
この例では、example_library
タイプのすべてのターゲットに暗黙的な
コンパイラ //tools:example_compiler
への依存関係があります。これにより、
呼び出すアクションを生成する example_library
の実装関数
ユーザーが自身のラベルを入力として渡さなかった場合でも、コンパイルされます。以降
_compiler
は非公開属性であり、ctx.attr._compiler
に従います。
このルールのすべてのターゲットで、常に //tools:example_compiler
を指します。
あります。または、compiler
使用し、デフォルト値のままにします。これによりユーザーは
必要な場合は別のコンパイラを使用しますが、コンパイラのバージョンを
ラベルです。
暗黙的な依存関係は通常、同じプロジェクトに存在する ルールの実装として使用します。ツールが 実行プラットフォームまたは別のリポジトリを使用する場合は、 ルールは、ツールチェーンからそのツールを取得する必要があります。
出力属性
出力属性(例: attr.output
、
attr.output_list
を指定するため、Cloud Storage バケットの
生成されます。これらは、次の 2 つの点で依存関係属性と異なります。
- 定義されたターゲットを参照する代わりに、出力ファイル ターゲットを定義します。 できます。
- 出力ファイルのターゲットは、インスタンスではなく、インスタンス化されたルール ターゲットに依存します。 その逆に変更できます。
通常、出力属性は、ルールで出力を作成する必要がある場合にのみ使用されます。
ユーザー定義の名前(ターゲット名に基づくことはできません)を使用します。ルールにすでに
1 つの出力属性で、通常は out
または outs
という名前が付けられます。
出力属性は、宣言された出力を作成するためのおすすめの方法です。 具体的に依存するか、 コマンドラインでリクエストできます。
実装関数
すべてのルールに implementation
関数が必要です。これらの関数は
分析フェーズに置いて、トレーニング コードを変換し、
読み込みフェーズで生成されたターゲットのグラフを、
実行フェーズで実行するアクション。そのため
実装関数で実際にファイルを読み書きすることはできません。
ルールの適用関数は通常、非公開です(名前の先頭に
(アンダースコア)。慣例的には、ルールと同じ名前が付けられますが、
_impl
で。
実装関数は 1 つのパラメータを取ります。
rule context(通常は ctx
という名前)このメソッドは、
プロバイダ
ターゲット
依存関係は、分析時に Target
として表されます。
説明します。これらのオブジェクトには、プロバイダが格納され、
ターゲットの実装関数が実行されました。
ctx.attr
には、それぞれの名前に対応するフィールドがあります。
各直接的な関係を表す Target
オブジェクトを含む
その属性を使用します。label_list
属性の場合、これは次のリストです。
Targets
。label
属性の場合、これは単一の Target
または None
です。
プロバイダ オブジェクトのリストは、ターゲットの実装関数によって返されます。
return [ExampleInfo(headers = depset(...))]
インデックス表記([]
)を使用してアクセスできます。プロバイダのタイプは次のとおりです。
できます。Starlark で定義されたカスタム プロバイダか、
ネイティブ ルールのプロバイダ(Starlark として利用可能)
使用します。
たとえば、ルールで hdrs
属性を使用してヘッダー ファイルを取得し、
ターゲットとそのコンシューマのコンパイル アクションに
次のように収集します。
def _example_library_impl(ctx):
...
transitive_headers = [hdr[ExampleInfo].headers for hdr in ctx.attr.hdrs]
従来の構造体スタイルがありますが、使用しないことを強くおすすめします。ルールを 移行したということです。
ファイル
ファイルは File
オブジェクトで表されます。Bazel は
分析フェーズでファイル I/O を実行する場合、これらのオブジェクトを
ファイル コンテンツを直接読み書きできます。むしろ、アクション生成ツールに渡され、
関数(ctx.actions
を参照)を使用して、
アクション グラフ。
File
は、ソースファイルまたは生成されたファイルのいずれかです。生成された各ファイル
1 つのアクションの出力にする必要があります。ソースファイルは、
できます。
各依存関係属性について、対応する
ctx.files
には、すべてのリソースのデフォルト出力のリストが
その属性を使用します。
def _example_library_impl(ctx):
...
headers = depset(ctx.files.hdrs, transitive = transitive_headers)
srcs = ctx.files.srcs
...
ctx.file
には、次の要素に対する単一の File
または None
が含まれています。
仕様で allow_single_file = True
が設定されている依存関係属性。
ctx.executable
は ctx.file
と同じように動作しますが、
仕様に executable = True
が設定されている依存関係属性のフィールドが含まれています。
出力の宣言
分析フェーズでは、ルールの実装関数で出力を作成できます。
読み込みフェーズではすべてのラベルを認識する必要があるため、
出力にラベルはありません。出力用の File
オブジェクトは、次のコマンドを使用して作成できます。
ctx.actions.declare_file
および
ctx.actions.declare_directory
。
多くの場合、出力の名前はターゲットの名前、
ctx.label.name
:
def _example_library_impl(ctx):
...
output_file = ctx.actions.declare_file(ctx.label.name + ".output")
...
事前に宣言された出力(Google 広告用に作成された出力など)
出力属性がありますが、代わりに File
オブジェクトを取得できます。
ctx.outputs
の対応するフィールドから取得できます。
操作
アクションは、一連の入力値から一連の出力を生成する方法を (例: 「hello.c で gcc を実行し、hello.o を取得する」)。アクションを作成すると、Bazel でアクション コマンドはすぐには実行されません。依存関係のグラフに登録します。 あるアクションが別のアクションの出力に依存する可能性があるためです。たとえば C では、 コンパイラの後にリンカーを呼び出す必要があります。
アクションを作成する汎用関数は、
ctx.actions
:
ctx.actions.run
: 実行可能ファイルを実行します。ctx.actions.run_shell
: シェルを実行します。 使用できます。ctx.actions.write
: 文字列をファイルに書き込みます。ctx.actions.expand_template
、 生成することもできます。
ctx.actions.args
を使用すると、
アクションの引数を蓄積できます。次の時点までデプセットのフラット化を回避
実行時間:
def _example_library_impl(ctx):
...
transitive_headers = [dep[ExampleInfo].headers for dep in ctx.attr.deps]
headers = depset(ctx.files.hdrs, transitive = transitive_headers)
srcs = ctx.files.srcs
inputs = depset(srcs, transitive = [headers])
output_file = ctx.actions.declare_file(ctx.label.name + ".output")
args = ctx.actions.args()
args.add_joined("-h", headers, join_with = ",")
args.add_joined("-s", srcs, join_with = ",")
args.add("-o", output_file)
ctx.actions.run(
mnemonic = "ExampleCompile",
executable = ctx.executable._compiler,
arguments = [args],
inputs = inputs,
outputs = [output_file],
)
...
アクションは入力ファイルのリストまたは依存関係を受け取り、入力ファイルのリスト(空でない)を生成します。 出力ファイルです。入力ファイルと出力ファイルのセットは、 分析フェーズに進みましょう。モデルのパフォーマンスに 属性など、依存関係のプロバイダもサポートしますが、 表示されます。たとえば、アクションで unzip コマンドを実行する場合、 では、インフレートするファイルを(unzip を実行する前に)指定する必要があります。 内部で可変数のファイルを内部に作成するアクションでは、それらを (zip、tar、その他のアーカイブ形式など)に圧縮できます。
アクションはすべての入力を列挙する必要があります。使用されていない入力の一覧表示 可能ですが、効率的ではありません。
アクションは、すべての出力を作成する必要があります。他のファイルを書き込むこともありますが、 出力に含まれないものは コンシューマは利用できなくなります宣言されたすべての出力 なんらかのアクションで書き込む必要があります。
アクションは純粋な関数に匹敵します。つまり、 使用せず、コンピュータ情報、ユーザー名、時計、パスワード、 ネットワーク、I/O デバイスなどです(入力の読み取りと出力の書き込みを除く)。これは、 出力がキャッシュに保存されて再利用されるため、重要です。
依存関係は Bazel によって解決されます。Bazel は、実行するアクションを決定します。 実行されます。依存関係グラフにサイクルがある場合はエラーになります。作成中 アクションの実行が保証されるわけではなく、 その出力がビルドに必要です。
プロバイダ
プロバイダは、ルールによって他のルールに公開され、 依存します。このデータには、渡す出力ファイル、ライブラリ、パラメータを含めることができます。 ツールのコマンドラインなど、ターゲットの利用者が知っておくべき 表示されます。
ルールの実装関数で読み取ることができるのは
ターゲットに即時に依存関係があり、依存関係を
依存関係からの情報(ターゲットの側で認識しておく必要がある)
消費者に対してリクエストできます。通常は、それを depset
に蓄積することで行います。
ターゲットのプロバイダは、 実装します。
古い実装関数は、以前のスタイルで記述することもできます。その場合、
実装関数は、値のリストではなく struct
を返します。
使用されます。このスタイルは使用しないことを強くおすすめします。ルールを
移行したということです。
デフォルトの出力
ターゲットの「デフォルトの出力」は、次の場合にデフォルトでリクエストされる出力です。
コマンドラインでビルドのターゲットがリクエストされます。たとえば、
java_library
のターゲット //pkg:foo
にはデフォルトの出力として foo.jar
があるため、
コマンド bazel build //pkg:foo
でビルドされます。
デフォルトの出力は、次の files
パラメータで指定されます。
DefaultInfo
:
def _example_library_impl(ctx):
...
return [
DefaultInfo(files = depset([output_file]), ...),
...
]
ルール実装または files
によって DefaultInfo
が返されない場合
パラメータが指定されていない場合、DefaultInfo.files
はデフォルトですべてに設定されます。
事前に宣言された出力(通常は outputs によって作成される出力)
属性)。
アクションを実行するルールは、その出力であっても、デフォルトの出力を提供する必要がある 直接使用することは想定されていません。グラフにないアクションは 出力がプルーニングされます。出力がターゲットのコンシューマによってのみ使用される場合、 ターゲットが独立して構築されている場合、これらのアクションは実行されません。この 失敗したターゲットのみを再構築することはできないため、デバッグが困難になります。 失敗を再現します
実行ファイル
実行ファイルは、(ビルドではなく)実行時にターゲットが使用するファイルのセット あります。実行フェーズで、Bazel は runfile を指すシンボリック リンクを含むディレクトリ ツリー。これにより、 実行時に実行ファイルにアクセスできるようにします。
Runfile はルールの作成時に手動で追加できます。
runfiles
オブジェクトは runfiles
メソッドで作成できます。
ルールのコンテキスト(ctx.runfiles
)で指定され、
DefaultInfo
の runfiles
パラメータ。実行可能な出力は、
実行可能ルールは暗黙的に runfile に追加されます。
一部のルールでは、属性を指定する属性で、通常は
data
: この出力は
ターゲットrunfile を実行します。Runfile も data
からマージする必要があります。
最終的に実行するためのコードを提供する可能性のある属性から
srcs
(data
が関連付けられた filegroup
個のターゲットを含む場合があります)と
deps
。
def _example_library_impl(ctx):
...
runfiles = ctx.runfiles(files = ctx.files.data)
transitive_runfiles = []
for runfiles_attr in (
ctx.attr.srcs,
ctx.attr.hdrs,
ctx.attr.deps,
ctx.attr.data,
):
for target in runfiles_attr:
transitive_runfiles.append(target[DefaultInfo].default_runfiles)
runfiles = runfiles.merge_all(transitive_runfiles)
return [
DefaultInfo(..., runfiles = runfiles),
...
]
カスタム プロバイダ
プロバイダは、provider
関数を使用してルール固有の情報を伝達します。
ExampleInfo = provider(
"Info needed to compile/link Example code.",
fields = {
"headers": "depset of header Files from transitive dependencies.",
"files_to_link": "depset of Files from compilation.",
},
)
その後、ルール実装関数でプロバイダ インスタンスを作成して返すことができます。
def _example_library_impl(ctx):
...
return [
...
ExampleInfo(
headers = headers,
files_to_link = depset(
[output_file],
transitive = [
dep[ExampleInfo].files_to_link for dep in ctx.attr.deps
],
),
)
]
プロバイダのカスタム初期化
カスタム コードでプロバイダのインスタンス化をガードすることで、 前処理と検証ロジックです。これを使用して よりクリーンな API をユーザーに提供するために、特定の不変条件を 取得できます。
これを行うには、init
コールバックを
provider
関数を使用します。このコールバックを指定すると、
provider()
の戻り値の型が、プロバイダ
シンボル(init
が使用されていないときの通常の戻り値)と、"raw"
あります。
この場合、プロバイダ シンボルが呼び出されたときに、元のアイテムが
引数が init
コールバックに転送されます。「
コールバックの戻り値は、フィールド名(文字列)を値にマッピングする辞書である必要があります。
これは新しいインスタンスのフィールドを初期化するために使用されます。なお、
コールバックには任意のシグネチャが存在する可能性があり、引数がシグネチャと一致しない場合
コールバックが直接呼び出された場合と同様にエラーが報告されます。
一方、未加工のコンストラクタは init
コールバックをバイパスします。
次の例では、init
を使用して引数の前処理と検証を行います。
# //pkg:exampleinfo.bzl
_core_headers = [...] # private constant representing standard library files
# Keyword-only arguments are preferred.
def _exampleinfo_init(*, files_to_link, headers = None, allow_empty_files_to_link = False):
if not files_to_link and not allow_empty_files_to_link:
fail("files_to_link may not be empty")
all_headers = depset(_core_headers, transitive = headers)
return {"files_to_link": files_to_link, "headers": all_headers}
ExampleInfo, _new_exampleinfo = provider(
fields = ["files_to_link", "headers"],
init = _exampleinfo_init,
)
ルールの実装では、次のようにプロバイダをインスタンス化できます。
ExampleInfo(
files_to_link = my_files_to_link, # may not be empty
headers = my_headers, # will automatically include the core headers
)
未加工のコンストラクタを使用して、代替のパブリック ファクトリ関数を定義できます。
init
ロジックを経由しない新しい API です。例: exampleinfo.bzl
次のように定義できます。
def make_barebones_exampleinfo(headers):
"""Returns an ExampleInfo with no files_to_link and only the specified headers."""
return _new_exampleinfo(files_to_link = depset(), headers = all_headers)
通常、未加工のコンストラクタは、名前が
アンダースコア(上記の _new_exampleinfo
)を使用して、ユーザーコードによって読み込めないようにし、
任意のプロバイダ インスタンスを生成します。
init
のもう 1 つの用途は、ユーザーがプロバイダを呼び出せないことです。
代わりにファクトリ関数を使用するように強制します。
def _exampleinfo_init_banned(*args, **kwargs):
fail("Do not call ExampleInfo(). Use make_exampleinfo() instead.")
ExampleInfo, _new_exampleinfo = provider(
...
init = _exampleinfo_init_banned)
def make_exampleinfo(...):
...
return _new_exampleinfo(...)
実行可能なルールとテストルール
実行可能なルールは、bazel run
コマンドで呼び出すことができるターゲットを定義します。
テストルールは特別な実行可能ルールで、そのターゲットも
bazel test
コマンドで呼び出されます。実行可能なルールとテストのルールは、
それぞれの executable
または
rule
の呼び出しの True
に test
引数を追加します。
example_binary = rule(
implementation = _example_binary_impl,
executable = True,
...
)
example_test = rule(
implementation = _example_binary_impl,
test = True,
...
)
テストルールの名前は、_test
で終わる必要があります。(ターゲット名も頻繁にテストする)
慣例により末尾は _test
ですが、必須ではありません)。テスト以外のルールでは、
という接尾辞が付いています。
どちらの種類のルールも、実行可能な出力ファイルを生成する必要がある(
事前に宣言されているものなど)であり、run
または test
コマンドによって呼び出されます。伝えるには
実行可能なファイルとして使用するルールの出力を Bazel で渡します。
返された DefaultInfo
の executable
引数
接続します。この executable
は、ルールのデフォルトの出力に追加されます(そのため、
executable
と files
の両方に渡す必要はありません)。また、これは暗黙的に
runfiles に追加します。
def _example_binary_impl(ctx):
executable = ctx.actions.declare_file(ctx.label.name)
...
return [
DefaultInfo(executable = executable, ...),
...
]
このファイルを生成するアクションでは、ファイルで実行可能ビットを設定する必要があります。対象
ctx.actions.run
または
この操作が必要な ctx.actions.run_shell
件のアクション
ベースとなるツールによってのみ取得されます。1 つの
ctx.actions.write
アクションの場合は、is_executable = True
を渡します。
従来の動作として、実行可能なルールには
事前定義された特殊な ctx.outputs.executable
出力。このファイルは
DefaultInfo
を使用して実行対象を指定しない場合は、デフォルトの実行可能ファイルであってはなりません
使用されます。この出力メカニズムは、
実行可能ファイル名を解析時にカスタマイズできます。
サンプル 実行可能ルール および test Rule です。
実行可能なルールと テストルールには、追加の 属性に加え、暗黙的に定義された属性も すべてのルール。デフォルトの 暗黙的に追加された属性は変更できませんが、回避することはできます Starlark マクロでプライベート ルールをラップして、 default:
def example_test(size = "small", **kwargs):
_example_test(size = size, **kwargs)
_example_test = rule(
...
)
実行ファイルの場所
bazel run
(または test
)を指定して実行可能ターゲットを実行すると、
runfiles ディレクトリは実行可能ファイルに隣接しているからです。パスは次のように関係します。
# Given launcher_path and runfile_file:
runfiles_root = launcher_path.path + ".runfiles"
workspace_name = ctx.workspace_name
runfile_path = runfile_file.short_path
execution_root_relative_path = "%s/%s/%s" % (
runfiles_root, workspace_name, runfile_path)
runfiles ディレクトリの下の File
へのパスは、
File.short_path
。
bazel
によって直接実行されるバイナリは、
runfiles
ディレクトリ。ただし、実行ファイルから呼び出されるバイナリは、
考えてみましょう。これを軽減するために、各バイナリは、
runfiles ルートをパラメータとして受け取るには、
指定することもできます。これにより、バイナリは正規の runfile ルートを正しく渡せるようになります。
バインドします。設定されていない場合、バイナリはそれが
最初のバイナリが呼び出され、隣接する runfiles ディレクトリを探します。
高度なトピック
出力ファイルのリクエスト
1 つのターゲットに複数の出力ファイルを含めることができます。bazel build
コマンドが
コマンドに指定されたターゲットの出力の一部が
リクエストできます。Bazel は、リクエストされたファイルと、Bazel がビルドしたファイルのみを
直接的か間接的かに依存します(アクション グラフの観点から見ると、Bazel は
依存関係として到達可能なアクションを実行します。
表示されます)。
デフォルトの出力に加えて、事前に宣言された出力では、
コマンドラインで明示的にリクエストできます。ルールでは、事前に宣言された
出力属性を使用して出力する。その場合、ユーザーは
ルールをインスタンス化する際に、出力のラベルを明示的に選択します。取得するには、
出力属性には File
オブジェクトを使用します。
ctx.outputs
の属性です。ルールでできること
事前に宣言された出力を暗黙的に定義する
も使用できますが、この機能は非推奨です。
デフォルトの出力の他に、出力グループがあります。これは、
まとめてリクエストできる出力ファイルの数を減らすことができます。これらの API は、
--output_groups
。対象
例: ターゲット //pkg:mytarget
が debug_files
のルールタイプの場合
出力グループがある場合、これらのファイルは bazel build //pkg:mytarget
--output_groups=debug_files
を実行してビルドできます。事前に宣言されていない出力にはラベルがないため、
その出力は、デフォルトの出力または出力コードで
できます。
出力グループは、
OutputGroupInfo
プロバイダ。多くのモデルとは異なり
組み込みプロバイダ。OutputGroupInfo
は任意の名前のパラメータを受け入れることができます。
その名前で出力グループを定義します。
def _example_library_impl(ctx):
...
debug_file = ctx.actions.declare_file(name + ".pdb")
...
return [
DefaultInfo(files = depset([output_file]), ...),
OutputGroupInfo(
debug_files = depset([debug_file]),
all_files = depset([output_file, debug_file]),
),
...
]
また、ほとんどのプロバイダとは異なり、OutputGroupInfo
は
aspect と、そのアスペクトが適用されるルール ターゲット。
同じ出力グループを定義しないようにしてください。その場合、結果の
統合されます。
なお、通常、OutputGroupInfo
は特定の並べ替えの指定に使用するべきではありません。
さまざまな形式のファイルをターゲットから
コンシューマのアクションまで拡張できます定義
ルール固有のプロバイダを使用してください。
構成
別のアーキテクチャ用の C++ バイナリをビルドするとします。「 構築は複雑で、複数のステップを必要とする場合があります。中級者向けには、 バイナリは、コンパイラやコード生成ツールなどのバイナリを 実行プラットフォーム(ホスト、 リモート エグゼキュータなど)。最終出力などの一部のバイナリは、 ターゲット アーキテクチャです。
そのため、Bazel には「構成」という概念があります。3 つあります「 最上位のターゲット(コマンドラインでリクエストされたもの)は、 target実行プラットフォームで実行する必要のあるツールは 「exec」が組み込まれているできます。ルールによって、生成されたアクションの 渡される CPU アーキテクチャを変更するなど 渡します。場合によっては、同じライブラリが複数の異なるタスクに対して できます。その場合は分析が行われ、場合によっては構築されます 複数回失敗します。
デフォルトでは、Bazel はターゲットの依存関係を つまり、遷移なしでターゲット自体が作成されます。依存関係が 必要な場合は、対応する属性を exec 構成への移行を指定しています。これにより、ツールとすべてのリソースが 実行プラットフォーム用にビルドされます
依存関係属性ごとに、cfg
を使用して、
同じ構成でビルドするか exec 構成に移行する必要があります。
依存関係属性に executable = True
フラグがある場合は、cfg
を設定する必要があります。
明示的に指定することもできます。これは、誤った目的のために誤ってツールを作成しないようにするためです。
できます。
例を見る
一般的に、開発時に必要になるソース、依存ライブラリ、実行可能ファイルは 同じ構成を使用できます。
ビルドの一環として実行されるツール(コンパイラやコード生成ツールなど)
exec 構成用にビルドする必要があります。この場合、cfg = "exec"
を
作成します。
それ以外の場合は、テストの一部としてなど、実行時に使用される実行可能ファイルに
構成する必要があります。この場合、cfg = "target"
を
作成します。
cfg = "target"
は実際には何も行いません。これは単に、
ルール設計者は意図を明確にできます。executable = False
の場合、
つまり、cfg
は省略可能で、読みやすくする場合にのみ設定してください。
また、cfg = my_transition
を使用して、
ユーザー定義の遷移
ルールの作成者は、構成の変更に非常に柔軟に対応できます。
Kubernetes の
ビルドグラフが大きくなり、わかりにくくなる。
注: 従来、Bazel には実行プラットフォームの概念がなく、 代わりに、すべてのビルド アクションがホストマシンで実行されるとみなされていました。Bazel バージョン 6.0 より前のバージョンでは、これを表す構成です 「host」への言及がある場合コードや古いドキュメントで 参照します。この追加の概念を回避するために、Bazel 6.0 以降を使用することをおすすめします。 オーバーヘッドを軽減できます。
構成フラグメント
ルールによりアクセスできる
構成フラグメント:
cpp
と java
。ただし、必要なフラグメントはすべて
次の点を確認してください。
def _impl(ctx):
# Using ctx.fragments.cpp leads to an error since it was not declared.
x = ctx.fragments.java
...
my_rule = rule(
implementation = _impl,
fragments = ["java"], # Required fragments of the target configuration
...
)
Runfiles のシンボリック リンク
通常、runfiles ツリー内のファイルの相対パスは、
ソースツリーまたは生成された出力ツリー内のそのファイルの相対パス。これらの
なんらかの理由で異なる必要がある場合は、root_symlinks
または
symlinks
引数。root_symlinks
は、パスをマッピングする辞書です。
ここで、パスは runfiles ディレクトリのルートからの相対パスです。「
symlinks
ディクショナリは同じですが、パスの先頭には暗黙的に
(メインのワークスペースを含むリポジトリの名前ではない)
現在の目標値など)が含まれます。
...
runfiles = ctx.runfiles(
root_symlinks = {"some/path/here.foo": ctx.file.some_data_file2}
symlinks = {"some/path/here.bar": ctx.file.some_data_file3}
)
# Creates something like:
# sometarget.runfiles/
# some/
# path/
# here.foo -> some_data_file2
# <workspace_name>/
# some/
# path/
# here.bar -> some_data_file3
symlinks
または root_symlinks
を使用する場合は、2 つの異なるテーブルをマッピングしないように注意してください。
runfiles ツリーの同じパスに配置する必要があります。この場合、ビルドは失敗します。
競合の説明エラーが表示されます修正するには、
ctx.runfiles
引数を指定して競合を解消します。このチェックは
そのルールを使用するすべてのターゲットと、それらのルールに依存する
できます。ツールが推移的に使用される可能性が高い場合、これは特に危険です
分析できます。シンボリック リンク名はツールのランファイル全体で一意である必要があり、
依存関係がすべて含まれます。
コード カバレッジ
coverage
コマンドを実行すると、
ビルドで、特定のターゲットに対するカバレッジ計測の追加が必要になる場合があります。「
build は、インストゥルメント化されるソースファイルのリストも収集します。サブセット
考慮されるターゲットは、フラグによって制御される
--instrumentation_filter
。
次の場合を除き、テスト ターゲットは除外されます。
--instrument_test_targets
指定されています。
ルールの実装でビルド時にカバレッジ計測を追加する場合は、
実装関数でそれを考慮する必要があります
ctx.coverage_instrumented の結果
ターゲットのソースをインストルメント化する必要がある場合、カバレッジ モードで True
:
# Are this rule's sources instrumented?
if ctx.coverage_instrumented():
# Do something to turn on coverage for this compile action
カバレッジ モードで常にオンにする必要があるロジック(ターゲットのソース (特にインストゥルメント化されているかどうか)に ctx.configuration.coverage_enabled.
コンパイル前にルールに依存関係のソースが直接含まれているかどうか コンパイル時のインストルメンテーションもオンにする必要がある場合があります。 依存関係がソースを計測可能にします。
# Are this rule's sources or any of the sources for its direct dependencies
# in deps instrumented?
if (ctx.configuration.coverage_enabled and
(ctx.coverage_instrumented() or
any([ctx.coverage_instrumented(dep) for dep in ctx.attr.deps]))):
# Do something to turn on coverage for this compile action
ルールでは、どの属性が関連する属性なのかを
InstrumentedFilesInfo
プロバイダによるカバレッジ。
coverage_common.instrumented_files_info
。
instrumented_files_info
の dependency_attributes
パラメータは、
すべてのランタイム依存関係属性(deps
や
data
などのデータ依存関係。source_attributes
パラメータは、
カバレッジ インストルメンテーションを追加できる場合は、ルールのソースファイルの属性を指定します。
def _example_library_impl(ctx):
...
return [
...
coverage_common.instrumented_files_info(
ctx,
dependency_attributes = ["deps", "data"],
# Omitted if coverage is not supported for this rule:
source_attributes = ["srcs", "hdrs"],
)
...
]
InstrumentedFilesInfo
が返されない場合、それぞれのデフォルト テーブルが作成されます。
ツール以外の依存関係属性が設定されていない
属性スキーマの cfg
から "exec"
。
dependency_attributes
。(属性を指定するため、これは理想的な動作ではありません。
dependency_attributes
の srcs
のように source_attributes
ではなく、
すべてのルールに対して明示的なカバレッジ構成を
必要があります。)
検証アクション
ビルドに関する情報や 検証に必要な情報は、アーティファクトでのみ利用可能 (ソースファイルまたは生成されたファイル)。この情報はアーティファクトに含まれるため、 ルールを読み込めないため、分析時にルールでこの検証を行うことができません。 できます。代わりに、アクションは実行時にこの検証を行う必要があります。日時 検証が失敗するとアクションも失敗し、ビルドも失敗します。
実施可能な検証の例としては、静的分析、lint チェック、 依存関係と整合性のチェック、スタイルのチェックがあります。
検証アクションは、部品を動かしてビルドのパフォーマンスを向上させるのにも役立ちます。 必要ないアクションを 1 つにまとめることができます。 たとえば、コンパイルと lint チェックを実行する単一のアクションを コンパイル アクションと lint チェック アクションに分けられ、その後、lint チェックが実行されます。 アクションを検証アクションとして実行し、他のアクションと並行して実行できます。
これらの「検証アクション」は他の場所で使用されるものは生成されず、 出力についてアサートするだけでよいためです。この 検証アクションを実行したときに結果が ルールがビルドの別の場所で使用されている場合、どのようにアクションが実行されるのでしょうか。 これまでは、検証アクションで空の文字列を出力する方法が採用されてきました。 その出力を、他の重要な入力要素に人為的に追加し、 アクションを実行します。
これは、コンパイル時に Bazel が常に検証アクションを実行するためです。 ただし、次のような大きなデメリットがあります。
検証アクションがビルドのクリティカル パスにある。Bazel は コンパイル アクションを実行するために空の出力が必要であると判断した場合、 入力が無視されますが、コンパイル アクションでは入力が無視されます。 これにより、並列処理が減り、ビルドが遅くなります。
代わりに、ビルド内の他のアクションが コンパイル アクションを実行する場合は、検証アクションの空の出力を
java_library
のソース jar 出力など)。これは、 コンパイル アクションの代わりに実行される可能性のある新しいアクションが 空の検証出力が誤って残されてしまう場合があります。
この問題を解決するには、Validations 出力グループを使用します。
検証出力グループ
Validations Output Group は、検証されていないものを保持するように設計された出力グループです。 出力を生成するため、人為的な出力を生成する必要は 他のアクションの入力に追加されます。
このグループは、特定のリソースに関係なく、常に出力がリクエストされる
--output_groups
フラグの値。ターゲットの状態は問いません。
たとえば、コマンドライン、依存関係として、あるいは
ターゲットの暗黙的な出力)。通常のキャッシュとインクリメンタリティ テストでは、
適用されます。検証アクションへの入力が変更されておらず、
成功した場合は、検証アクションは
あります。
この出力グループを使用する場合も、検証アクションでなんらかのファイルを出力する必要があります。 空のオブジェクトも作成できます。そのため、通常はサポートされないツールをラップする必要が ファイルを作成するように出力を作成します。
次の 3 つのケースでは、ターゲットの検証アクションは実行されません。
- ターゲットがツールとして依存している場合
- ターゲットが暗黙的な依存関係( 「_」で始まる属性)
- ターゲットが exec 構成に組み込まれているとき。
これらのターゲットには、それぞれ固有の ビルドとテストを分離し、検証の失敗を発見できるようにします。
Validations 出力グループの使用
検証出力グループは _validation
という名前で、他のテストと同様に使用されます。
出力グループ:
def _rule_with_validation_impl(ctx):
ctx.actions.write(ctx.outputs.main, "main output\n")
ctx.actions.write(ctx.outputs.implicit, "implicit output\n")
validation_output = ctx.actions.declare_file(ctx.attr.name + ".validation")
ctx.actions.run(
outputs = [validation_output],
executable = ctx.executable._validation_tool,
arguments = [validation_output.path],
)
return [
DefaultInfo(files = depset([ctx.outputs.main])),
OutputGroupInfo(_validation = depset([validation_output])),
]
rule_with_validation = rule(
implementation = _rule_with_validation_impl,
outputs = {
"main": "%{name}.main",
"implicit": "%{name}.implicit",
},
attrs = {
"_validation_tool": attr.label(
default = Label("//validation_actions:validation_tool"),
executable = True,
cfg = "exec"
),
}
)
検証出力ファイルは DefaultInfo
または
フィルタできます。このルール種類のターゲットの検証アクション
ターゲットがラベルまたはターゲットの
暗黙的な出力は、直接的または間接的に依存しています。
通常、検証アクションの出力は、Cloud Storage バケットに 他のアクションの入力には追加されず、他のアクションの入力には 並列処理のメリットを失う可能性があります。ただし、Bazel は これを適用するための特別なチェックがあります。そのため 検証アクションの出力が、任意のアクションの入力に追加されることが Starlark ルール用のテストです。例:
load("@bazel_skylib//lib:unittest.bzl", "analysistest")
def _validation_outputs_test_impl(ctx):
env = analysistest.begin(ctx)
actions = analysistest.target_actions(env)
target = analysistest.target_under_test(env)
validation_outputs = target.output_groups._validation.to_list()
for action in actions:
for validation_output in validation_outputs:
if validation_output in action.inputs.to_list():
analysistest.fail(env,
"%s is a validation action output, but is an input to action %s" % (
validation_output, action))
return analysistest.end(env)
validation_outputs_test = analysistest.make(_validation_outputs_test_impl)
検証アクション フラグ
検証アクションの実行は --run_validations
コマンドラインで制御されます。
デフォルトは true です。
サポートが終了した機能
非推奨の事前宣言済み出力
事前に宣言された出力を使用する際は、次の 2 つの方法があります(非推奨)。
rule
のoutputs
パラメータでは、 出力属性名と文字列テンプレート間のマッピングを 出力ラベルを使用します。事前定義された宣言されていない出力とDefaultInfo.files
に出力を明示的に追加する。ルールのターゲットの 入力としてラベルを使用するルールの場合、これは事前に宣言された あります。実行可能ルールの場合、
ctx.outputs.executable
は ルールの対象と同じ名前の、事前に宣言された実行可能な出力に変換できます。 出力は明示的に宣言することをおすすめします。たとえば、ctx.actions.declare_file(ctx.label.name)
です。このコマンドは、 実行可能なファイルを生成するため、実行を許可するように権限を設定します。明示的 実行可能な出力をDefaultInfo
のexecutable
パラメータに渡します。
避けるべき実行ファイルの機能
ctx.runfiles
と runfiles
タイプには複雑な機能セットがあり、その多くは以前の理由で保持されています。
次の推奨事項は複雑さの軽減に役立ちます。
次の
collect_data
モードとcollect_default
モードは使用しないctx.runfiles
。これらのモードは、 特定のハードコードされた依存関係エッジで runfile を実行することで、混乱を招きます。 代わりに、次のfiles
パラメータまたはtransitive_files
パラメータを使用してファイルを追加します。ctx.runfiles
を使用するか、依存関係にある実行ファイルをrunfiles = runfiles.merge(dep[DefaultInfo].default_runfiles)
。次のプロトコルの
data_runfiles
とdefault_runfiles
は使用しないでください。DefaultInfo
コンストラクタ。代わりにDefaultInfo(runfiles = ...)
を指定してください。 「デフォルト」と「data」runfile は できます。たとえば、一部のルールはデフォルトの出力をdata_runfiles
。default_runfiles
は不可。代わりに、data_runfiles
: ルールにデフォルトの出力を含めることと、マージする両方が必要 実行ファイルを提供する属性からのdefault_runfiles
(data
)。DefaultInfo
からrunfiles
を取得するとき(通常は統合のためのみ) 現在のルールとその依存関係の間のファイルを実行する場合は、DefaultInfo.data_runfiles
ではなく、DefaultInfo.default_runfiles
です。
以前のプロバイダからの移行
従来、Bazel プロバイダは Target
オブジェクト上の単純なフィールドでした。。
ドット演算子を使用してアクセスされており、
ルールの ID で返される struct
で
実装関数を使用します。
return struct(example_info = struct(headers = depset(...)))
このようなプロバイダは、Target
オブジェクトの対応するフィールドから取得できます。
transitive_headers = [hdr.example_info.headers for hdr in ctx.attr.hdrs]
このスタイルは非推奨となっているため、新しいコードでは使用しないでください。詳しくは、 移行に役立つ情報をご確認ください。新しいプロバイダ メカニズムでは、名前が 防ぐことができます。データの非表示もサポートします。つまり、すべてのコードが プロバイダ シンボルを使用して取得します。
現時点では、従来のプロバイダは引き続きサポートされます。1 つのルールで、 簡単に説明します。
def _old_rule_impl(ctx):
...
legacy_data = struct(x = "foo", ...)
modern_data = MyInfo(y = "bar", ...)
# When any legacy providers are returned, the top-level returned value is a
# struct.
return struct(
# One key = value entry for each legacy provider.
legacy_info = legacy_data,
...
# Additional modern providers:
providers = [modern_data, ...])
このルールのインスタンスの結果の Target
オブジェクトが dep
である場合、
プロバイダとそのコンテンツは dep.legacy_info.x
として取得でき、
dep[MyInfo].y
。
返される構造体には、providers
以外にも、
特殊な意味を持つ(対応するレガシー モデルが作成されない)
あります。
フィールド
files
、runfiles
、data_runfiles
、default_runfiles
、executable
は、同じ名前を持つフィールドに対応します。DefaultInfo
。次のいずれかを指定することはできません。DefaultInfo
プロバイダも返します。フィールド
output_groups
は構造体値を取り、OutputGroupInfo
。
provides
のルール宣言内、および
providers
の依存関係宣言
従来のプロバイダは文字列として渡され、最新のプロバイダは
Info
記号で渡されます。必ず文字列から記号に変更してください
おすすめします更新が困難な複雑なルールセットや大規模なルールセットの場合
すべてのルールをアトミックに実行するため、
手順:
レガシー プロバイダを生成するルールを変更して、レガシー プロバイダと 最新のプロバイダを柔軟に実装できます宣言するルールでは、 以前のプロバイダを返す場合は、宣言を更新して、以前のプロバイダと サポートしています。
以前のプロバイダを使用するルールを変更して、代わりに 最新のプロバイダですいずれかの属性宣言で以前のプロバイダが必要な場合は、 最新のプロバイダを要求するように更新することもできます。必要に応じて、 この作業をステップ 1 でインターリーブするために、コンシューマが provider: 以前のプロバイダが存在するかどうかをテストします。
hasattr(target, 'foo')
、またはFooInfo in target
を使用する新しいプロバイダ。以前のプロバイダをすべてのルールから完全に削除します。