ビルド時または実行時に A
が B
を必要とする場合、ターゲット A
はターゲット B
に依存します。「依存」関係では、ターゲットに対して有向非巡回グラフ(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
の依存関係の推移的クロージャ全体を検査し、これらのターゲットの変更が最終結果に反映されるようにし、必要に応じて中間を再構築します。
依存関係の推移的性質はよくある間違いにつながります。1 つのファイル内のコードが、間接的依存関係によって提供されるコードを使用する場合があります。これは、宣言された依存関係グラフにおける直接的なエッジではなく、推移的ですが直接的なエッジです。間接依存関係は 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 ファイル | 公開設定 |