Bazel は、他のプロジェクトのターゲットに依存することがあります。このような他のプロジェクトからの依存関係は、外部依存関係と呼ばれます。
ワークスペース ディレクトリの WORKSPACE
ファイル(または WORKSPACE.bazel
ファイル)で、他のプロジェクトのソースを取得する方法を Bazel に指示できます。これらの他のプロジェクトには、独自のターゲットを持つ 1 つ以上の BUILD
ファイルを含めることができます。メイン プロジェクト内の BUILD
ファイルは、WORKSPACE
ファイルにある名前を使用することで、これらの外部ターゲットに依存できます。
たとえば、システムに 2 つのプロジェクトがあるとします。
/
home/
user/
project1/
WORKSPACE
BUILD
srcs/
...
project2/
WORKSPACE
BUILD
my-libs/
project1
が /home/user/project2/BUILD
で定義されているターゲット :foo
に依存する必要がある場合は、project2
という名前のリポジトリが /home/user/project2
にあることを指定できます。この場合、/home/user/project1/BUILD
内のターゲットは @project2//:foo
に依存することになります。
WORKSPACE
ファイルを使用すると、ファイル システムの他の部分にあるターゲットやインターネットからダウンロードしたターゲットに依存できます。BUILD
ファイルと同じ構文を使用しますが、リポジトリ ルールと呼ばれる別のルールセットを使用できます(ワークスペース ルールとも呼ばれます)。Bazel には、いくつかの組み込みリポジトリ ルールと、一連の埋め込みの Starlark リポジトリ ルールが用意されています。カスタム リポジトリ ルールを作成して、より複雑な動作を行うこともできます。
サポートされている外部依存関係のタイプ
いくつかの基本的なタイプの外部依存関係を使用できます。
他の Bazel プロジェクトに依存
2 つ目の Bazel プロジェクトのターゲットを使用する場合は、local_repository
、git_repository
、http_archive
のいずれかを使用して、ローカル ファイルシステムからシンボリック リンクするか、Git リポジトリを参照するか、ダウンロードします。
たとえば、作業しているプロジェクト my-project/
が、同僚のプロジェクト coworkers-project/
のターゲットに依存するとします。どちらのプロジェクトも Bazel を使用するため、同僚のプロジェクトを外部依存関係として追加し、同僚が自分の BUILD ファイルから定義したターゲットを使用できます。my_project/WORKSPACE
に次のように追加します。
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
同僚がターゲット //foo:bar
を使用している場合、プロジェクトでそれを @coworkers_project//foo:bar
として参照できます。外部プロジェクト名は、有効なワークスペース名にする必要があります。
Bazel 以外のプロジェクトに依存
new_local_repository
などの new_
で始まるルールを使用すると、Bazel を使用しないプロジェクトからターゲットを作成できます。
たとえば、作業しているプロジェクト my-project/
が同僚のプロジェクト coworkers-project/
に依存するとします。同僚のプロジェクトでは make
を使用してビルドしていますが、生成された .so ファイルの 1 つに依存したいと考えています。そのためには、次のコードを my_project/WORKSPACE
に追加します。
new_local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
build_file = "coworker.BUILD",
)
build_file
は、既存のプロジェクトにオーバーレイする BUILD
ファイルを指定します。次に例を示します。
cc_library(
name = "some-lib",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
これで、プロジェクトの BUILD
ファイルの @coworkers_project//:some-lib
に依存できるようになります。
外部パッケージに依存
Maven アーティファクトとリポジトリ
ルールセット rules_jvm_external
を使用して、Maven リポジトリからアーティファクトをダウンロードして、Java の依存関係として使用できるようにします。
依存関係をフェッチする
デフォルトでは、外部依存関係は bazel build
中に必要に応じて取得されます。特定のターゲット セットに必要な依存関係をプリフェッチする場合は、bazel fetch
を使用します。すべての外部依存関係を無条件にフェッチするには、bazel sync
を使用します。フェッチされたリポジトリは出力ベースに格納されるため、取得はワークスペースごとに行われます。
依存関係のシャドーイング
可能な限り、プロジェクトには単一のバージョン ポリシーを設定することをおすすめします。これは、コンパイルして最終的なバイナリになる依存関係に必要です。ただし、これが当てはまらない場合は、依存関係をシャドーイングできます。次のシナリオを考えてみます。
myproject/WorkSPACE
workspace(name = "myproject")
local_repository(
name = "A",
path = "../A",
)
local_repository(
name = "B",
path = "../B",
)
A/WORKSPACE
workspace(name = "A")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "...",
)
B/Workspace
workspace(name = "B")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
依存関係 A
と B
はどちらも testrunner
に依存していますが、異なるバージョンの testrunner
に依存しています。これらのテストランナーが myproject
内で平和に共存しない理由はありませんが、同じ名前のテストランナーは競合します。両方の依存関係を宣言するには、myproject/WORKSPACE を更新します。
workspace(name = "myproject")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner-v1",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "..."
)
http_archive(
name = "testrunner-v2",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
local_repository(
name = "A",
path = "../A",
repo_mapping = {"@testrunner" : "@testrunner-v1"}
)
local_repository(
name = "B",
path = "../B",
repo_mapping = {"@testrunner" : "@testrunner-v2"}
)
このメカニズムは、ダイヤモンドの接合にも使用できます。たとえば、A
と B
に同じ依存関係があり、名前が異なると、これらの依存関係を myproject/WORKSPACE で結合できます。
コマンドラインからリポジトリをオーバーライドする
コマンドラインからローカル リポジトリを使用して、宣言されたリポジトリをオーバーライドするには、--override_repository
フラグを使用します。このフラグを使用すると、ソースコードを変更せずに外部リポジトリの内容を変更できます。
たとえば、@foo
をローカル ディレクトリ /path/to/local/foo
にオーバーライドするには、--override_repository=foo=/path/to/local/foo
フラグを渡します。
ユースケースの一部を示します。
- 問題のデバッグ。たとえば、
http_archive
リポジトリをローカル ディレクトリにオーバーライドすると、変更が容易になります。 - ベンダー化。ネットワーク呼び出しできない環境では、代わりにローカル ディレクトリを指すようにネットワーク ベースのリポジトリ ルールをオーバーライドします。
プロキシの使用
Bazel は、HTTPS_PROXY
環境変数と HTTP_PROXY
環境変数からプロキシ アドレスを取得し、これを使用して HTTP/HTTPS ファイルをダウンロードします(指定されている場合)。
IPv6 のサポート
IPv6 専用マシンでは、Bazel を変更せずに依存関係をダウンロードできます。ただし、デュアルスタックの IPv4/IPv6 マシンでは、Bazel は Java と同じ規則に従います。IPv4 が有効になっている場合は、IPv4 が優先されます。たとえば、IPv4 ネットワークで外部アドレスを解決できない、または外部アドレスに到達できない場合、Network unreachable
例外が発生し、ビルドが失敗することがあります。このような場合、java.net.preferIPv6Addresses=true
システム プロパティを使用して Bazel の動作をオーバーライドして IPv6 を優先できます。以下にご紹介します。
--host_jvm_args=-Djava.net.preferIPv6Addresses=true
起動オプションを使用します。たとえば、.bazelrc
ファイルに次の行を追加します。startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true
インターネットに接続する必要がある Java ビルド ターゲットを実行している場合は(統合テストで必要な場合もあります)、
--jvmopt=-Djava.net.preferIPv6Addresses=true
ツールフラグも使用します。たとえば、.bazelrc
ファイルに次の行を追加します。build --jvmopt=-Djava.net.preferIPv6Addresses
たとえば、依存関係のバージョンを解決するために rules_jvm_external を使用している場合は、
COURSIER_OPTS
環境変数に-Djava.net.preferIPv6Addresses=true
を追加して、Coursier 用の JVM オプションを指定することもできます。
推移的依存関係
Bazel は、WORKSPACE
ファイルにリストされている依存関係のみを読み取ります。プロジェクト(A
)が、WORKSPACE
ファイルに 3 つ目のプロジェクト(C
)への依存関係を記述している別のプロジェクト(B
)に依存している場合は、B
と C
の両方をプロジェクトの WORKSPACE
ファイルに追加する必要があります。この要件は WORKSPACE
ファイルサイズを膨張させることができますが、あるライブラリにバージョン 1.0 の C
が含まれ、別のライブラリに 2.0 の C
が含まれる可能性が制限されます。
外部依存関係のキャッシュ保存
デフォルトでは、Bazel は外部依存関係の定義が変更された場合にのみ、外部依存関係を再ダウンロードします。定義内で参照されるファイル(パッチや BUILD
ファイルなど)の変更も bazel で考慮されます。
強制的に再ダウンロードするには、bazel sync
を使用します。
レイアウト
外部依存関係はすべて、出力ベースのサブディレクトリ external
の下にあるディレクトリにダウンロードされます。ローカル リポジトリの場合は、新しいディレクトリを作成する代わりに、シンボリック リンクが作成されます。以下を実行すると、external
ディレクトリを表示できます。
ls $(bazel info output_base)/external
bazel clean
を実行しても、外部ディレクトリが実際に削除されるわけではありません。すべての外部アーティファクトを削除するには、bazel clean --expunge
を使用します。
オフライン ビルド
ビルドをオフラインで実行するのが望ましい場合があります。飛行機での移動などの単純なユースケースでは、必要なリポジトリを bazel fetch
または bazel sync
でプリフェッチするだけで十分です。さらに、ビルド中にオプション --nofetch
を使用して、それ以上のリポジトリの取得を無効にすることもできます。
真のオフライン ビルド(必要なファイルの提供を bazel とは異なるエンティティによって行う場合)の場合、bazel はオプション --distdir
をサポートします。リポジトリ ルールが bazel に ctx.download
または ctx.download_and_extract
を介してファイルを取得するよう要求し、必要なファイルのハッシュサムを提供すると、bazel は最初にそのオプションで指定されたディレクトリを調べ、指定された最初の URL のベース名に一致するファイルを探し、ハッシュが一致する場合はそのローカルコピーを使用します。
Bazel 自体は、この手法を使用して配布アーティファクトからオフラインをブートストラップします。これは、内部 distdir_tar
に必要なすべての外部依存関係を収集することで実現されます。
ただし、bazel では、リポジトリ ルールで任意のコマンドを、ネットワークを呼び出すかどうかに関係なく実行できます。そのため、bazel にはビルドを完全にオフラインにするオプションはありません。そのため、ビルドがオフラインで正しく機能するかどうかをテストするには、bazel のブートストラップ テストのように、ネットワークの外部ブロックが必要です。
ベスト プラクティス
リポジトリのルール
通常、リポジトリ ルールでは次のことを行います。
- システム設定を検出してファイルに書き込む。
- システム上の別の場所でリソースを検索する。
- URL からリソースをダウンロードします。
- BUILD ファイルを生成または外部リポジトリ ディレクトリにシンボリック リンクします。
可能であれば、repository_ctx.execute
は使用しないでください。たとえば、Make を使用したビルドを含む Bazel 以外の C++ ライブラリを使用している場合は、ctx.execute(["make"])
を実行する代わりに、repository_ctx.download()
を使用してビルドする BUILD ファイルを書き込むことをおすすめします。
git_repository
と new_git_repository
よりも http_archive
を優先します。その理由は次のとおりです。
- Git リポジトリ ルールはシステムの
git(1)
に依存しますが、HTTP ダウンローダーは Bazel に組み込まれており、システムの依存関係はありません。 http_archive
はurls
のリストをミラーとしてサポートし、git_repository
は単一のremote
のみをサポートします。http_archive
はリポジトリ キャッシュでは動作しますが、git_repository
は動作しません。詳しくは、#5116 をご覧ください。
bind()
を使用しない。この問題とその代替方法については、バインドの削除を検討するをご覧ください。