ルール

<ph type="x-smartling-placeholder"></ph> 問題を報告する ソースを表示 夜間 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

ルールは、Bazel で実行される一連のアクションを定義します。 出力のセットを生成するための入力です。この出力は、 ルールの ID によって返されるプロバイダ 実装関数。たとえば、C++ バイナリルールの例:

  1. .cpp ソースファイル(入力)のセットを取得します。
  2. ソースファイルに対して g++ を実行します(アクション)。
  3. 実行可能な出力とその他のファイルで DefaultInfo プロバイダを返す 実行時に利用できるようにします
  4. 取得した C++ 固有の情報を使用して CcInfo プロバイダを返します。 その依存関係を定義します。

Bazel の観点からは、g++ と標準の C++ ライブラリも入力です 追加します。ルールライターは、ユーザーが指定するルールだけでなく、 ルールの実行に必要なツールとライブラリも できます。

ルールを作成または変更する前に、Bazel の ビルドフェーズ。データ アナリストは、 (読み込み、分析、実行)。また、kubectl の マクロについて学び、ルールとルールの違いを理解する マクロ。使用を開始するには、まずルールのチュートリアルをご覧ください。 このページを参照用として使用します。

Bazel 自体には、いくつかのルールが組み込まれています。次のようなネイティブ ルールcc_libraryjava_binary は、特定の言語のコアサポートを提供します。 独自のルールを定義することで、言語とツールに対する同様のサポートを追加できます。 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 を参照するか、 依存関係のグラフを作成します。

ルール固有の属性(srcsdeps など)は、マップを渡すことで定義します。 属性名からスキーマ(attr を使用して作成)に モジュール)を ruleattrs パラメータに追加します。 一般的な属性: namevisibility は、すべてのルールに暗黙的に追加されます。追加 各属性が暗黙的に追加され、 実行可能ルールとテストルールを具体的に指定します。属性 暗黙的にルールに追加され、 attrs

依存関係属性

通常、ソースコードを処理するルールでは、 さまざまな種類の依存関係があります。

  • srcs には、ターゲットのアクションで処理されるソースファイルを指定します。多くの場合、 属性スキーマは、並べ替えに必要なファイル拡張子を指定します ソースファイルを指定します。ヘッダー ファイルを使用する言語のルール 通常は、商品またはサービスによって処理されるヘッダーに、個別の hdrs 属性を 把握することです
  • deps は、ターゲットのコード依存関係を指定します。属性スキーマは それらの依存関係が提供する必要があるプロバイダを指定します。( たとえば、cc_libraryCcInfo を提供します)。
  • 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_targetmy_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.outputattr.output_list を指定するため、Cloud Storage バケットの 生成されます。これらは、次の 2 つの点で依存関係属性と異なります。

  • 定義されたターゲットを参照する代わりに、出力ファイル ターゲットを定義します。 できます。
  • 出力ファイルのターゲットは、インスタンスではなく、インスタンス化されたルール ターゲットに依存します。 その逆に変更できます。

通常、出力属性は、ルールで出力を作成する必要がある場合にのみ使用されます。 ユーザー定義の名前(ターゲット名に基づくことはできません)を使用します。ルールにすでに 1 つの出力属性で、通常は out または outs という名前が付けられます。

出力属性は、宣言された出力を作成するためのおすすめの方法です。 具体的に依存するか、 コマンドラインでリクエストできます。

実装関数

すべてのルールに implementation 関数が必要です。これらの関数は 分析フェーズに置いて、トレーニング コードを変換し、 読み込みフェーズで生成されたターゲットのグラフを、 実行フェーズで実行するアクション。そのため 実装関数では、実際にファイルを読み書きすることはできません。

ルールの適用関数は通常、非公開です(名前の先頭に (アンダースコア)。慣例的には、ルールと同じ名前が付けられますが、 _impl で。

実装関数は 1 つのパラメータを取ります。 rule context(通常は ctx という名前)このメソッドは、 プロバイダ

ターゲット

依存関係は、分析時に Target として表されます。 説明します。これらのオブジェクトには、プロバイダが格納され、 ターゲットの実装関数が実行されました。

ctx.attr には、それぞれの名前に対応するフィールドがあります。 各直接的な関係を表す Target オブジェクトを含む その属性を介して依存関係を設定します。label_list 属性の場合、これは次のリストです。 Targetslabel 属性の場合、これは単一の 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]

struct が ターゲットの実装関数を使用します。

return struct(example_info = struct(headers = depset(...)))

プロバイダは、Target オブジェクトの対応するフィールドから取得できます。

transitive_headers = [hdr.example_info.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.executablectx.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.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 に蓄積することで行います。

ターゲットのプロバイダは、Provider 実装します。

古い実装関数は、以前のスタイルで記述することもできます。その場合、 実装関数は、値のリストではなく 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)で指定され、 DefaultInforunfiles パラメータ。実行可能な出力は、 実行可能ルールは暗黙的に runfile に追加されます。

一部のルールでは、属性を指定する属性で、通常は data: この出力は ターゲットrunfile を実行します。Runfile も data からマージする必要があります。 最終的に実行するためのコードを提供する可能性のある属性から srcsdata が関連付けられた 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

# It's possible to define an init accepting positional arguments, but
# 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(
    ...
    init = _exampleinfo_init)

export ExampleInfo

ルールの実装では、次のようにプロバイダをインスタンス化できます。

    ExampleInfo(
        files_to_link=my_files_to_link,  # may not be empty
        headers = my_headers,  # will automatically include the core headers
    )

未加工のコンストラクタを使用して、代替のパブリック ファクトリ関数を定義できます。 init ロジックを経由しない新しい関数を作成できます。たとえば、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 の呼び出しの Truetest 引数を追加します。

example_binary = rule(
   implementation = _example_binary_impl,
   executable = True,
   ...
)

example_test = rule(
   implementation = _example_binary_impl,
   test = True,
   ...
)

テストルールの名前は、_test で終わる必要があります。(ターゲット名も頻繁にテストする) 慣例により末尾は _test ですが、必須ではありません)。テスト以外のルールでは、 という接尾辞が付いています。

どちらの種類のルールも、実行可能な出力ファイルを生成する必要がある( 事前に宣言されているものなど)であり、run または test コマンドによって呼び出されます。伝えるには 実行可能なファイルとして使用するルールの出力を Bazel で渡します。 返された DefaultInfoexecutable 引数 接続します。この executable は、ルールのデフォルトの出力に追加されます(そのため、 executablefiles の両方に渡す必要はありません)。また、これは暗黙的に 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:mytargetdebug_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]),
        ),
        ...
    ]

また、ほとんどのプロバイダとは異なり、OutputGroupInfoaspect と、そのアスペクトが適用されるルール ターゲット。 同じ出力グループを定義しないようにしてください。その場合、結果の 統合されます。

なお、通常、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 には実行プラットフォームの概念がなく、 代わりに、すべてのビルド アクションがホストマシンで実行されるとみなされていました。 このため、単一の「ホスト」と「host」というラベルが付きます。移行 依存関係を構築するために使用できます。多数のルール 「host」という語はツールの移行について考えていますが、現時点では 「exec」を使用するように移行される行うことをおすすめします。

「ホスト」クラスタと「exec」は構成:

  • 「host」「exec」はターミナル依存関係が「host」フォルダ内にあると、 それ以上の移行は許可されません。さらに アプリケーションの構成をできます。
  • 「host」モノリシックであり「host」は 1 つだけ構成、 別の「エグゼクティブ」と構成する必要があります 説明します。
  • 「host」Bazel と同じマシンまたは 実行されるようにします。これはもはや当てはまらず、 ローカル マシン、またはリモート エグゼキュータ上でのアクションを実行できると、 リモート エグゼキュータの CPU と OS がローカル あります。

「エグゼクティブ」は「host」同じオプションの変更が適用されます(たとえば、 --compilation_mode--host_compilation_mode から設定し、--cpu を次の値から設定します: --host_cpu など)。違いは、「ホスト」始まりは その他すべてのフラグの default 値を使用し、"exec" は構成 ターゲット構成に基づいて、フラグの現在の値から始まります。

構成フラグメント

ルールによりアクセスできる 構成フラグメント: cppjavajvm。ただし、必要なフラグメントはすべて 次の点を確認してください。

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
    host_fragments = ["java"], # Required fragments of the host configuration
    ...
)

ctx.fragments がターゲットの構成フラグメントのみを提供する できます。ホスト設定のフラグメントにアクセスするには、次のコマンドを使用します。 代わりに ctx.host_fragments を使用してください。

通常、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_infoinstrumented_files_infodependency_attributes パラメータは、 すべてのランタイム依存関係属性(depsdata などのデータ依存関係。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"host" または "exec"dependency_attributes。(属性を指定するため、これは理想的な動作ではありません。 dependency_attributessrcs のように source_attributes ではなく、 すべてのルールに対して明示的なカバレッジ構成を 必要があります。)

検証アクション

ビルドに関する情報や 検証に必要な情報は、アーティファクトでのみ利用可能 (ソースファイルまたは生成されたファイル)。この情報はアーティファクトに含まれるため、 ルールを読み込めないため、分析時にルールでこの検証を行うことはできません。 できます。代わりに、アクションは実行時にこの検証を行う必要があります。日時 検証が失敗するとアクションも失敗し、ビルドも失敗します。

実施可能な検証の例としては、静的分析、lint チェック、 依存関係と整合性のチェック、スタイルのチェックがあります。

検証アクションは、部品を動かしてビルドのパフォーマンスを向上させるのにも役立ちます。 必要ないアクションを 1 つにまとめることができます。 たとえば、コンパイルと lint チェックを実行する単一のアクションを コンパイル アクションと lint チェック アクションに分けられ、その後、lint チェックが実行されます。 アクションを検証アクションとして実行し、他のアクションと並行して実行できます。

これらの「検証アクション」は他の場所で使用されるものは生成されず、 出力についてアサートするだけでよいためです。この 問題があります。検証アクションによって結果が生成されることが ルールがビルドの別の場所で使用されている場合、どのようにアクションが実行されるのでしょうか。 これまでは、検証アクションで空の文字列を出力する方法が採用されてきました。 その出力を、他の重要な入力要素に人為的に追加し、 アクションを実行します。

これは、コンパイル時に Bazel が常に検証アクションを実行するためです。 ただし、次のような大きなデメリットがあります。

  1. 検証アクションがビルドのクリティカル パスにある。Bazel は コンパイル アクションを実行するために空の出力が必要であると判断した場合、 入力が無視されますが、コンパイル アクションでは入力が無視されます。 これにより、並列処理が減り、ビルドが遅くなります。

  2. 代わりに、ビルド内の他のアクションが コンパイル アクションを実行する場合は、検証アクションの空の出力を java_library のソース jar 出力など)。これは、 コンパイル アクションの代わりに実行される可能性のある新しいアクションが 空の検証出力が誤って残されてしまう場合があります。

この問題を解決するには、Validations 出力グループを使用します。

検証出力グループ

Validations Output Group は、検証されていないものを保持するように設計された出力グループです。 出力を生成するため、人為的な出力を生成する必要は 他のアクションの入力に追加されます。

このグループは、特定のリソースに関係なく、常に出力がリクエストされる --output_groups フラグの値。ターゲットの状態は問いません。 たとえば、コマンドライン、依存関係として、あるいは ターゲットの暗黙的な出力)。通常のキャッシュとインクリメンタリティ テストでは、 適用されます。検証アクションへの入力が変更されておらず、 成功した場合は、検証アクションは あります。

この出力グループを使用する場合も、検証アクションでなんらかのファイルを出力する必要があります。 空のオブジェクトも作成できます。そのため、通常はサポートされないツールをラップする必要が ファイルを作成するように出力を作成します。

次の 3 つのケースでは、ターゲットの検証アクションは実行されません。

  • ターゲットがツールとして依存している場合
  • ターゲットが暗黙的な依存関係( 「_」で始まる属性)
  • ターゲットが host または 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 つの方法があります(非推奨)。

  • ruleoutputs パラメータでは、 出力属性名と文字列テンプレート間のマッピングを 出力ラベルを使用します。事前定義された宣言されていない出力と DefaultInfo.files に出力を明示的に追加する。ルールのターゲットの 入力としてラベルを使用するルールの場合、これは事前に宣言された あります。

  • 実行可能ルールの場合、ctx.outputs.executable は ルールの対象と同じ名前の、事前に宣言された実行可能な出力に変換できます。 出力は明示的に宣言することをおすすめします。たとえば、 ctx.actions.declare_file(ctx.label.name) です。このコマンドは、 実行可能なファイルを生成するため、実行を許可するように権限を設定します。明示的 実行可能な出力を DefaultInfoexecutable パラメータに渡します。

避けるべき実行ファイルの機能

ctx.runfilesrunfiles タイプには複雑な機能セットがあり、その多くは以前の理由で保持されています。 次の推奨事項は複雑さの軽減に役立ちます。

  • 次の collect_data モードと collect_default モードは使用しない ctx.runfiles。これらのモードは、 特定のハードコードされた依存関係エッジで runfile を実行することで、混乱を招きます。 代わりに、次の files パラメータまたは transitive_files パラメータを使用してファイルを追加します。 ctx.runfiles を使用するか、依存関係にある実行ファイルを runfiles = runfiles.merge(dep[DefaultInfo].default_runfiles)

  • 次のプロトコルの data_runfilesdefault_runfiles使用しないでください。 DefaultInfo コンストラクタ。代わりに DefaultInfo(runfiles = ...) を指定してください。 「デフォルト」と「data」runfile は できます。たとえば、一部のルールはデフォルトの出力を data_runfilesdefault_runfiles は不可。代わりに、 data_runfiles: ルールにデフォルトの出力を含めることと、マージする両方が必要 実行ファイルを提供する属性からの default_runfilesdata)。

  • DefaultInfo から runfiles を取得するとき(通常は統合のためのみ) 現在のルールとその依存関係の間のファイルを実行する場合は、 DefaultInfo.data_runfiles ではなくDefaultInfo.default_runfiles です。

以前のプロバイダからの移行

従来、Bazel プロバイダは Target オブジェクト上の単純なフィールドでした。。 ドット演算子を使用してアクセスされており、 ルールの実装関数によって返される構造体です。

このスタイルはサポートが終了しているため、新しいコードでは使用しないでください。詳しくは、 移行に役立つ情報をご確認ください。新しいプロバイダ メカニズムでは、名前が 防ぐことができます。データの非表示もサポートします。つまり、すべてのコードが プロバイダ シンボルを使用して取得します。

現時点では、従来のプロバイダは引き続きサポートされます。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 以外にも、 特殊な意味を持つ(対応するレガシー モデルが作成されない) あります。

  • フィールド filesrunfilesdata_runfilesdefault_runfilesexecutable は、同じ名前を持つフィールドに対応します。 DefaultInfo。次のいずれかを指定することはできません。 DefaultInfo プロバイダも返します。

  • フィールド output_groups は構造体値を取り、 OutputGroupInfo

provides のルール宣言内、および providers の依存関係宣言 従来のプロバイダは文字列として渡され、最新のプロバイダは *Info 記号で渡されます。必ず文字列から記号に変更してください おすすめします更新が困難な複雑なルールセットや大規模なルールセットの場合 すべてのルールをアトミックに実行するため、 手順:

  1. レガシー プロバイダを生成するルールを変更して、レガシー プロバイダと 最新のプロバイダをサポートしています。宣言するルールでは、 以前のプロバイダを返す場合は、宣言を更新して、以前のプロバイダと サポートしています。

  2. 以前のプロバイダを使用するルールを変更して、代わりに 最新のプロバイダですいずれかの属性宣言で以前のプロバイダが必要な場合は、 最新のプロバイダを要求するように更新することもできます。必要に応じて、 この作業とステップ 1 をインターリーブするために、コンシューマがどちらかの provider: 以前のプロバイダが存在するかどうかをテストします。 hasattr(target, 'foo')、または FooInfo in target を使用する新しいプロバイダ。

  3. 以前のプロバイダをすべてのルールから完全に削除します。