依存関係

問題を報告 ソースを表示 Nightly · 7.4 . 7.3 7.2 7.1 7.0 6.5

ビルド時または実行時に BA によって必要とされる場合は、ターゲット A はターゲット B依存しますdepends upon 関係は、ターゲットに対して有向非巡回グラフ(DAG)を誘導します。これは依存関係グラフと呼ばれます。

ターゲットの直接的依存関係とは、パスによって到達可能な他のターゲットのことです。 長さ 1 のテーブルが作成されます。ターゲットの推移的依存関係は、 グラフ内の任意の長さのパスを介して、依存するターゲットをリストします。

実際のところ、ビルドのコンテキストでは、実際の依存関係のグラフと宣言された依存関係のグラフの 2 つの依存関係グラフがあります。ほとんどの場合、2 つのグラフは非常に類似しているため、この区別を行う必要はありませんが、以下の説明では役に立ちます。

実際の依存関係と宣言された依存関係

X が正しくビルドされるためには Y が存在し、ビルドされ、最新の状態である必要がある場合、ターゲット X はターゲット Y実際に依存しています。ビルドとは、生成、処理、コンパイル、リンク、アーカイブ、圧縮、実行など、ビルド中に日常的に発生するタスクのいずれかを指します。

ターゲット X にターゲット Y に対する依存関係が宣言されている(依存関係がある場合) X のパッケージで X から Y へのエッジ。

正しいビルドの場合、実際の依存関係のグラフ A は、宣言された依存関係のグラフ D のサブグラフである必要があります。つまり、A の直接接続されたノード x --> y のペアはすべて、D でも直接接続されている必要があります。DA過近似と言えます。

BUILD ファイル ライターは、すべてのルールの実際の直接依存関係をすべてビルドシステムに明示的に宣言する必要があります。

この原則に従わないと、未定義の動作が発生します。ビルドが失敗し、 さらに悪いことに、ビルドが以前のオペレーションに依存したり、推移的 依存関係が宣言されます。Bazel による欠落チェック エラーが報告されますが、このチェックを 完了しています。

間接的にインポートされたすべてをリストに含める必要はありません。 (実行時に A によって必要とされる場合でも)。

ターゲット X のビルド中に、ビルドツールは推移的全体を検査します。 X の依存関係を閉じて、それらのターゲットの変更が確実に適用されるようにします。 最終結果に反映され、必要に応じて中間体が再構築されます。

依存関係の推移的な性質が、よくある間違いにつながります。場合によっては あるファイル内のコードで、間接的な依存関係によって 推移的であるが直接的なエッジではない。間接的 BUILD ファイルに依存関係が含まれていない。ルールはプロバイダに直接依存しないため、次のタイムラインの例に示すように、変更を追跡する方法はありません。

1. 宣言された依存関係が実際の依存関係と一致する

最初はすべて正常に動作します。パッケージ a のコードは、パッケージ b のコードを使用します。パッケージ b のコードはパッケージ c のコードを使用しているため、ac に間接的に依存しています。

a/BUILD b/BUILD
rule(
    name = "a",
    srcs = "a.in",
    deps = "//b:b",
)
      
rule(
    name = "b",
    srcs = "b.in",
    deps = "//c:c",
)
      
a / a.in b / b.in
import b;
b.foo();
    
import c;
function foo() {
  c.bar();
}
      
a、b、c を矢印で結んだ宣言された依存関係グラフ
宣言された依存関係グラフ
宣言された依存関係と一致する実際の依存関係グラフ
                  a、b、c を結ぶ矢印の付いたグラフ
実際の依存関係グラフ

宣言された依存関係が実際の依存関係を過大評価している。順調です。

2. 宣言されていない依存関係を追加する

誰かが a にコードを追加すると、潜在的な危険が引き起こされます。 c への直接的な依存関係があるが、ビルドファイルでの宣言を忘れている a/BUILD

a / a.in  
        import b;
        import c;
        b.foo();
        c.garply();
      
 
a、b、c を接続する矢印がある宣言された依存関係グラフ
宣言された依存関係グラフ
a、b、c を矢印で結んだ実際の依存関係グラフ。「
                  矢印 A を C にも接続します。これは次と一致しません:
                  宣言された依存関係グラフ
実際の依存関係グラフ

宣言された依存関係が実際の依存関係を過大評価しなくなりました。 2 つのグラフの推移閉包が等しいため、この場合、ビルドは正常に完了する可能性がありますが、問題が隠蔽されます。a には c に対する実際の依存関係がありますが、宣言されていません。

3. 宣言された依存関係グラフと実際の依存関係グラフの差異

b をリファクタリングして c に依存しないようにすると、誰かが自分の過失ではなく、意図せず a を破壊し、このハザードが明らかになります。

  b/BUILD
 
rule(
    name = "b",
    srcs = "b.in",
    deps = "//d:d",
)
      
  b / b.in
 
      import d;
      function foo() {
        d.baz();
      }
      
a と b を接続する矢印で宣言された依存関係グラフ。b が c に接続しなくなったため、a と c の接続が切断される
宣言された依存関係グラフ
b と c への接続を示す実際の依存関係グラフ。
                  b はもはや c に接続しない
実際の依存関係グラフ

宣言された依存関係グラフは、実際の 推移的閉じている場合でも、依存関係をその可能性が高くなります。

この問題は、ステップ 2 で導入した a から c への実際の依存関係が BUILD ファイルで適切に宣言されていれば回避できたでしょう。

依存関係の種類

ほとんどのビルドルールには、リソースの種類を指定する 3 つの属性があります。 汎用依存関係: srcsdepsdata以下で説明します。対象 詳細については、以下をご覧ください。 すべてのルールに共通する属性

多くのルールには、ルール固有の依存関係(compilerresources など)の追加属性もあります。これらの詳細については 百科事典を作成する

srcs の依存関係

ソースファイルを出力するルールによって直接使用されるファイル。

deps 依存関係

ヘッダー ファイルを提供する個別にコンパイルされたモジュールを指すルール シンボル、ライブラリ、データなど

data の依存関係

ビルド ターゲットが正しく実行するために、データファイルが必要になる場合があります。これらのデータファイルは ソースコードではありません。ターゲットのビルド方法には影響しません。たとえば、 単体テストでは、関数の出力とファイルの内容を比較する場合があります。ユーザーが 単体テストを作成します。このファイルは必要なく、 テストします。実行中に起動するツールについても同様です。

ビルドシステムは、隔離されたディレクトリでテストを実行します。このディレクトリには、 data は利用できます。したがって、バイナリ、ライブラリ、テストの実行にファイルが必要な場合は、それらのファイル(またはそれらを含むビルドルール)を data に指定します。例:

# I need a config file from a directory named env:
java_binary(
    name = "setenv",
    ...
    data = [":env/default_env.txt"],
)

# I need test data from another directory
sh_test(
    name = "regtest",
    srcs = ["regtest.sh"],
    data = [
        "//data:file1.txt",
        "//data:file2.txt",
        ...
    ],
)

これらのファイルには、相対パス path/to/data/file を使用してアクセスできます。テストでは テストのソースのパスを結合することで、これらのファイルを参照できます。 ディレクトリとワークスペースの相対パス(例: ${TEST_SRCDIR}/workspace/path/to/data/file

ラベルを使用したディレクトリの参照

BUILD ファイルを調べると、一部の data ラベルがディレクトリを参照していることがわかります。次の例のように、これらのラベルは /. または / で終わります。使用しないでください。

非推奨 - data = ["//data/regression:unittest/."]

非推奨 - data = ["testdata/."]

非推奨 - data = ["testdata/"]

これは特にテストには便利であるように思える。 ディレクトリ内のすべてのデータファイルを使用します。

ただし、このようなことは行わないでください。変更後に正しい増分再ビルド(およびテストの再実行)を行うには、ビルド(またはテスト)への入力となるファイルの完全なセットをビルドシステムが認識している必要があります。このように 場合、ビルドシステムは、ディレクトリ自体が (ファイルの追加や削除によって)行われたものの、変更を検出して 個々のファイルの編集は、包含するディレクトリには影響しないため、それらの変更は行いません。 ビルドシステムへの入力としてディレクトリを指定するのではなく、明示的に、または glob() 関数を使用して、ディレクトリ内のファイルのセットを列挙する必要があります。(** を使用して、 glob() は再帰的になります)。

推奨 - data = glob(["testdata/**"])

ただし、ディレクトリラベルを使用しなければならないシナリオもあります。たとえば、testdata ディレクトリに、名前がラベル構文に準拠していないファイルが含まれている場合、ファイルの明示的な列挙または glob() 関数の使用により、無効なラベルエラーが発生します。この場合はディレクトリラベルを使用する必要がありますが、上記の不正な再ビルドのリスクに注意してください。

ディレクトリラベルを使用する必要がある場合は、相対 ../ パスで親パッケージを参照することはできません。代わりに、//data/regression:unittest/. などの絶対パスを使用します。

複数のファイルを使用する必要があるテストなどの外部ルールは、 明示的に宣言する必要があります。filegroup() を使用して、BUILD ファイルでファイルをグループ化できます。

filegroup(
        name = 'my_data',
        srcs = glob(['my_unittest_data/*'])
)

その後、テストでデータ依存関係としてラベル my_data を参照できます。

BUILD ファイル 公開設定