ビルド時または実行時に B
が A
によって必要とされる場合は、ターゲット A
はターゲット B
に依存します。depends upon 関係は、ターゲットに対して有向非巡回グラフ(DAG)を誘導します。これは依存関係グラフと呼ばれます。
ターゲットの直接依存関係とは、依存関係グラフ内の長さ 1 のパスで到達できる他のターゲットです。ターゲットの推移的依存関係とは、グラフ上の任意の長さのパスを通じてターゲットが依存するターゲットです。
実際のところ、ビルドのコンテキストでは、実際の依存関係のグラフと宣言された依存関係のグラフの 2 つの依存関係グラフがあります。ほとんどの場合、2 つのグラフは非常に類似しているため、この区別を行う必要はありませんが、以下の説明では役に立ちます。
実際の依存関係と宣言された依存関係
ターゲット X
がターゲット Y
に実際に依存している場合、X
を正しくビルドするには Y
が存在し、ビルドされ、最新の状態である必要があります。ビルドとは、生成、処理、コンパイル、リンク、アーカイブ、圧縮、実行など、ビルド中に日常的に発生するタスクのいずれかを指します。
X
のパッケージに X
から Y
への依存関係エッジがある場合、ターゲット X
にはターゲット Y
に対する宣言された依存関係があります。
正しいビルドでは、実際の依存関係 A のグラフが、宣言された依存関係 D のグラフのサブグラフである必要があります。つまり、A で直接接続されるノード x --> y
のペアはすべて、D で直接接続される必要があります。D は A の過剰近似であると言えます。
BUILD
ファイル ライターは、ビルドシステムに対する各ルールの実際の直接的な依存関係をすべて明示的に宣言する必要があります。
この原則に従わないと、未定義の動作が発生します。ビルドが失敗する可能性がありますが、さらに悪いことに、ビルドが以前のオペレーションに依存する可能性があります。また、ターゲットが偶然持っている伝播宣言された依存関係に依存する可能性があります。Bazel は不足している依存関係をチェックし、エラーを報告しますが、このチェックをすべてのケースで完了することはできません。
実行時に A
によって必要と判断された場合でも、間接的にインポートされたすべてのものを一覧表示する必要はありません(また、表示しないことをおすすめします)。
ターゲット X
のビルド中に、ビルドツールは X
の依存関係の完全な推移閉包を検査し、これらのターゲットの変更が最終結果に反映されるようにします。必要に応じて中間ファイルを再ビルドします。
依存関係の推移的な性質が、よくある間違いにつながります。あるファイル内のコードでは、間接的な依存関係によって提供されるコードを使用することがあります。これは、宣言された依存関係グラフにおける推移的エッジであり、直接的なエッジではありません。間接的な依存関係は BUILD
ファイルに表示されません。ルールはプロバイダに直接依存していないため、次のタイムライン例に示すように、変更を追跡する方法はありません。
1. 宣言された依存関係が実際の依存関係と一致している
最初はすべて正常に動作します。パッケージ a
のコードは、パッケージ b
のコードを使用します。パッケージ b
のコードはパッケージ c
のコードを使用しているため、a
は c
に間接的に依存しています。
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(); } |
宣言された依存関係が実際の依存関係を過剰に近似している。問題ありません。
2. 宣言されていない依存関係の追加
c
に対する直接の実際の依存関係を作成するコードを a
に追加し、ビルドファイル a/BUILD
で宣言し忘れると、潜在的なハザードが導入されます。
a / a.in |
|
---|---|
import b; import c; b.foo(); c.garply(); |
|
宣言された依存関係が実際の依存関係を過剰に近似しなくなりました。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(); } |
|
宣言された依存関係グラフは、推移的に閉じた場合でも実際の依存関係の過小近似値になります。ビルドが失敗する可能性があります。
この問題は、ステップ 2 で導入した a
から c
への実際の依存関係が BUILD
ファイルで適切に宣言されていれば回避できたでしょう。
依存関係の種類
ほとんどのビルドルールには、さまざまな種類の汎用依存関係を指定する 3 つの属性(srcs
、deps
、data
)があります。以下で説明します。詳細については、すべてのルールに共通する属性をご覧ください。
多くのルールには、ルール固有の依存関係(compiler
や resources
など)の追加属性もあります。詳しくは、Build Encyclopedia をご覧ください。
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 ファイル | 公開設定 |