ビルド イベント プロトコルの例

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

Build Event Protocol の完全な仕様については、そのプロトコル 使用します。ただし、なんらかの直感を身につけておくと、 確認する必要があります

2 つの空のシェル スクリプトで構成される単純な Bazel ワークスペースについて考えてみましょう。 foo.shfoo_test.sh、および次の BUILD ファイル:

sh_library(
    name = "foo_lib",
    srcs = ["foo.sh"],
)

sh_test(
    name = "foo_test",
    srcs = ["foo_test.sh"],
    deps = [":foo_lib"],
)

このプロジェクトで bazel test ... を実行すると、生成された結果のビルドグラフが表示されます。 ビルドイベントは下のグラフのようになります矢印は 前述した親子関係によって決まります。なお、一部のビルドイベントと 簡略化のためにほとんどのフィールドは省略されています。

ベップグラフ

図 1. BEP グラフ。

最初に BuildStarted イベントがパブリッシュされます。このイベントから bazel test コマンドでビルドが呼び出され、子イベントが通知されます。

  • OptionsParsed
  • WorkspaceStatus
  • CommandLine
  • UnstructuredCommandLine
  • BuildMetadata
  • BuildFinished
  • PatternExpanded
  • Progress

最初の 3 つのイベントは、Bazel の呼び出し方法に関する情報を提供します。

PatternExpanded ビルドイベントによって分析情報が提供される ... パターンが展開され、特定のターゲットに展開されます。 //foo:foo_lib//foo:foo_test。そのために、この変数に TargetConfigured イベントを子として割り当てます。TargetConfigured イベントは、 Configuration であっても、Configuration イベントを子イベントとして宣言します。 TargetConfigured イベントの前に投稿されました。

親と子の関係のほかに、イベントは相互を参照する場合もあります。 ビルドイベント識別子を使用しますたとえば、上のグラフでは、 TargetComplete イベントは、fileSetsNamedSetOfFiles イベントを参照します。 表示されます。

通常、ファイルを参照するビルドイベントにファイルが埋め込まれない イベント内の名前とパスです。代わりに、ビルドイベント ID が含まれます。 NamedSetOfFiles イベント。これには実際のファイル名と あります。NamedSetOfFiles イベントを使用すると、一連のファイルを 1 回報告し、 多くのターゲットから参照されます。この構造が必要になるのは、 場合によっては、Build Event Protocol の出力サイズが 最適化されます。NamedSetOfFiles イベントにファイルの一部が含まれていない場合もあります。 代わりに他の NamedSetOfFiles イベントを ビルドイベント識別子。

以下は、//foo:foo_libTargetComplete イベントのインスタンスです。 プロトコル バッファの JSON 表現で出力されます。 ビルドイベント ID には、ターゲットが不透明な文字列として含まれており、 ビルドイベント ID を使用して Configuration イベント。このイベントは すべての子イベントを通知しますペイロードには、リクエストが ターゲットが正常にビルドされたかどうか、出力ファイルのセット、ターゲットの種類が確認できます。 構築しました。

{
  "id": {
    "targetCompleted": {
      "label": "//foo:foo_lib",
      "configuration": {
        "id": "544e39a7f0abdb3efdd29d675a48bc6a"
      }
    }
  },
  "completed": {
    "success": true,
    "outputGroup": [{
      "name": "default",
      "fileSets": [{
        "id": "0"
      }]
    }],
    "targetKind": "sh_library rule"
  }
}

BEP での Aspect 結果

通常のビルドは、(target, configuration) に関連付けられたアクションを評価します。 あります。アスペクトを有効にしてビルドすると、Bazel さらに、指定された有効なアスペクトの影響を受けるターゲットごとに、(target, configuration, aspect) 個のトリプルに関連付けられたターゲットを評価します。

アスペクトの評価結果は、 イベントタイプを指定します。(target, configuration) ペアごとに、 Bazel は追加の TargetConfigured を発行し、 TargetComplete アスペクトを あります。たとえば、//:foo_lib--aspects=aspects/myaspect.bzl%custom_aspect、この予定は次の場所でも表示されます BEP:

{
  "id": {
    "targetCompleted": {
      "label": "//foo:foo_lib",
      "configuration": {
        "id": "544e39a7f0abdb3efdd29d675a48bc6a"
      },
      "aspect": "aspects/myaspect.bzl%custom_aspect"
    }
  },
  "completed": {
    "success": true,
    "outputGroup": [{
      "name": "default",
      "fileSets": [{
        "id": "1"
      }]
    }]
  }
}

NamedSetOfFiles の消費

特定の標的(またはアスペクト)によって生成されたアーティファクトを決定することは、一般的です。 ある程度の準備をすれば効率的に実行できる BEP のユースケース。このセクション NamedSetOfFiles によって提供される再帰の共有構造について説明します。 このイベントは、Starlark Depset の構造と一致します。

消費者は処理時に二次アルゴリズムを避けるように注意する必要がある NamedSetOfFiles イベントを発生させます。これは、大規模なビルドには何万ものビルドが含まれることがあるためです。 トラバーサルで数億件のオペレーションを必要とするため、 二次複雑度です。

namedsetoffiles-bep-graph

図 2. NamedSetOfFiles BEP グラフ。

NamedSetOfFiles イベントは、常に BEP ストリームの次のに表示されます。 それを参照する TargetComplete イベントまたは NamedSetOfFiles イベント。これが 「親子」の逆数最初のイベントは 1 つのみとなります。 少なくとも 1 つのイベントがそれを発表した後に表示されます。NamedSetOfFiles イベントは (セマンティクスのない Progress イベント)で通知されるイベントです。

順序と共有に関するこうした制約を考慮すると、一般的なコンシューマでは、 NamedSetOfFiles イベントを保持し、BEP ストリームがなくなるまで待機します。次の JSON イベント ストリームと Python コードで、イベントストリームから 「デフォルト」のビルド アーティファクトのターゲット/アスペクト出力グループ、さらには ビルドされたターゲット/アスペクトのサブセットの出力を処理します。

named_sets = {}  # type: dict[str, NamedSetOfFiles]
outputs = {}     # type: dict[str, dict[str, set[str]]]

for event in stream:
  kind = event.id.WhichOneof("id")
  if kind == "named_set":
    named_sets[event.id.named_set.id] = event.named_set_of_files
  elif kind == "target_completed":
    tc = event.id.target_completed
    target_id = (tc.label, tc.configuration.id, tc.aspect)
    outputs[target_id] = {}
    for group in event.completed.output_group:
      outputs[target_id][group.name] = {fs.id for fs in group.file_sets}

for result_id in relevant_subset(outputs.keys()):
  visit = outputs[result_id].get("default", [])
  seen_sets = set(visit)
  while visit:
    set_name = visit.pop()
    s = named_sets[set_name]
    for f in s.files:
      process_file(result_id, f)
    for fs in s.file_sets:
      if fs.id not in seen_sets:
        visit.add(fs.id)
        seen_sets.add(fs.id)