外部依存関係の概要

Bazel は、ワークスペースにないビルドで使用される外部依存関係、ソースファイル(テキストとバイナリの両方)をサポートしています。たとえば、GitHub リポジトリでホストされているルールセット、Maven アーティファクト、現在のワークスペース外のローカルマシンのディレクトリなどです。

このドキュメントでは、システムの概要を説明してから、いくつかのコンセプトについて詳しく説明します。

システムの概要

Bazel の外部依存関係システムは、バージョン管理された Bazel プロジェクトである Bazel モジュールと、ソースファイルを含むディレクトリ ツリーであるリポジトリ(またはリポジトリ)に基づいて動作します。

Bazel はルート モジュール(作業中のプロジェクト)から開始します。すべてのモジュールと同様に、ディレクトリのルートに MODULE.bazel ファイルがあり、基本的なメタデータと直接の依存関係を宣言する必要があります。基本的な例を次に示します。

module(name = "my-module", version = "1.0")

bazel_dep(name = "rules_cc", version = "0.1.1")
bazel_dep(name = "platforms", version = "0.0.11")

そこから、Bazel はすべての推移的依存関係モジュールを Bazel レジストリ(デフォルトでは Bazel Central Registry)で検索します。レジストリは依存関係の MODULE.bazel ファイルを提供します。これにより、Bazel はバージョン解決を実行する前に、推移的依存関係グラフ全体を検出できます。

バージョン解決(各モジュールに 1 つのバージョンが選択される)の後、Bazel はレジストリを再度参照して、各モジュールのリポジトリを定義する方法(各依存関係モジュールのソースを取得する方法)を確認します。ほとんどの場合、これらはインターネットからダウンロードして抽出したアーカイブです。

モジュールは、タグと呼ばれるカスタマイズされたデータの一部を指定することもできます。これは、モジュール解決後に モジュール拡張機能によって使用され、追加のリポジトリを定義します。これらの拡張機能は、ファイル I/O やネットワーク リクエストの送信などのアクションを実行できます。これらにより、Bazel モジュールから構築された依存関係グラフを尊重しながら、Bazel が他のパッケージ管理システムとやり取りできるようになります。

3 種類のリポジトリ(メイン リポジトリ(作業中のソースツリー)、推移的依存関係モジュールを表すリポジトリ、モジュール拡張機能によって作成されたリポジトリ)が、ワークスペースを構成します。外部リポジトリ(メイン以外のリポジトリ)は、オンデマンドでフェッチされます。たとえば、BUILD ファイルのラベル(@repo//pkg:target など)で参照されている場合などです。

利点

Bazel の外部依存関係システムには、さまざまなメリットがあります。

依存関係の自動解決

  • 決定論的バージョン解決: Bazel は決定論的 MVS バージョン解決アルゴリズムを採用し、競合を最小限に抑え、ダイヤモンド依存関係の問題に対処します。
  • 依存関係の管理の簡素化: MODULE.bazel は直接の依存関係のみを宣言し、推移的な依存関係は自動的に解決されるため、プロジェクトの依存関係の概要をより明確に把握できます。
  • 厳密な依存関係の可視性: 直接の依存関係のみが表示され、正確性と予測可能性が確保されます。

エコシステムの統合

  • Bazel Central Registry: Bazel モジュールとして共通の依存関係を検出して管理するための一元化されたリポジトリ。
  • Bazel 以外のプロジェクトの採用: Bazel 以外のプロジェクト(通常は C++ ライブラリ)が Bazel に適応され、BCR で利用可能になると、コミュニティ全体での統合が効率化され、カスタム BUILD ファイルの重複した作業や競合が解消されます。
  • 言語固有のパッケージ マネージャーとの統合の統一: ルールセットにより、Bazel 以外の依存関係の外部パッケージ マネージャーとの統合が合理化されます。たとえば、次のものがあります。

高度な機能

  • モジュール拡張機能: use_repo_rule とモジュール拡張機能を使用すると、カスタム リポジトリ ルールと解決ロジックを柔軟に使用して、Bazel 以外の依存関係を導入できます。
  • bazel mod コマンド: このサブコマンドは、外部依存関係を検査する強力な方法を提供します。外部依存関係がどのように定義され、どこから発生しているかを正確に把握できます。
  • ベンダーモード: オフライン ビルドを容易にするために必要な外部依存関係を正確にプリフェッチします。
  • ロックファイル: ロックファイルにより、ビルドの再現性が向上し、依存関係の解決が高速化されます。
  • (近日リリース)BCR 系統証明書: 依存関係の検証済み系統を確保することで、サプライ チェーンのセキュリティを強化します。

コンセプト

このセクションでは、外部依存関係に関連するコンセプトについて詳しく説明します。

モジュール

複数のバージョンを持つことができる Bazel プロジェクト。各バージョンは他のモジュールに依存関係を持つことができます。

ローカル Bazel ワークスペースでは、モジュールはリポジトリで表されます。

詳細については、Bazel モジュールをご覧ください。

リポジトリ

ルートに境界マーカー ファイルがあり、Bazel ビルドで使用できるソースファイルを含むディレクトリ ツリー。多くの場合、単に repo と略されます。

リポジトリ境界マーカー ファイルは、MODULE.bazel(このリポジトリが Bazel モジュールを表すことを示す)、REPO.bazel下記を参照)、またはレガシー コンテキストでは WORKSPACE または WORKSPACE.bazel になります。リポジトリ境界マーカー ファイルはリポジトリの境界を示します。このようなファイルは、ディレクトリ内に複数存在できます。

メイン リポジトリ

現在の Bazel コマンドが実行されているリポジトリ。

メイン リポジトリのルートは、ワークスペース ルートとも呼ばれます。

ワークスペース

すべての Bazel コマンドで共有される環境は、同じメイン リポジトリで実行されます。これには、メイン リポジトリと定義されたすべての外部リポジトリのセットが含まれます。

これまで、「リポジトリ」と「ワークスペース」の概念が混同されてきたことに注意してください。「ワークスペース」という用語は、メイン リポジトリを指すために使用されることが多く、場合によっては「リポジトリ」の同義語として使用されることもあります。

正規リポジトリ名

リポジトリが常にアドレス指定可能な名前。ワークスペースのコンテキスト内では、各リポジトリに 1 つの正規名があります。正規名が canonical_name のリポジトリ内のターゲットは、ラベル @@canonical_name//package:target でアドレス指定できます(@ が 2 つあることに注意してください)。

メイン リポジトリの正規名は常に空の文字列です。

リポジトリの表示名

特定のリポジトリのコンテキストでリポジトリをアドレス指定できる名前。これはリポジトリの「ニックネーム」と考えることができます。正規名 michael のリポジトリは、リポジトリ alice のコンテキストでは mike という名前で表示されることがありますが、リポジトリ bob のコンテキストでは mickey という名前で表示されることがあります。この場合、michael 内のターゲットは、alice のコンテキストでラベル @mike//package:target によってアドレス指定できます(@ は 1 つだけです)。

逆に、これはリポジトリ マッピングと考えることができます。各リポジトリは、「見かけ上のリポジトリ名」から「正規のリポジトリ名」へのマッピングを保持します。

リポジトリ ルール

リポジトリを具体化する方法を Bazel に指示するリポジトリ定義のスキーマ。たとえば、「特定の URL から zip アーカイブをダウンロードして展開する」、「特定の Maven アーティファクトを取得して java_import ターゲットとして使用できるようにする」、「ローカル ディレクトリをシンボリック リンクする」などです。すべてのリポジトリは、適切な数の引数を使用してリポジトリルールを呼び出すことで定義されます。

独自のリポジトリルールを作成する方法については、リポジトリルールをご覧ください。

最も一般的な repo ルールは、URL からアーカイブをダウンロードして抽出する http_archive と、すでに Bazel リポジトリであるローカル ディレクトリをシンボリック リンクする local_repository です。

リポジトリをフェッチする

関連付けられた repo ルールを実行して、ローカル ディスクで repo を使用できるようにするアクション。ワークスペースで定義されたリポジトリは、取得されるまでローカル ディスクで使用できません。

通常、Bazel はリポジトリから何かが必要で、リポジトリがまだ取得されていない場合にのみリポジトリを取得します。リポジトリがすでにフェッチされている場合、Bazel は定義が変更された場合にのみ再フェッチします。

fetch コマンドを使用すると、リポジトリ、ターゲット、またはビルドを実行するために必要なすべてのリポジトリのプリフェッチを開始できます。この機能により、--nofetch オプションを使用してオフライン ビルドが可能になります。

--fetch オプションは、ネットワーク アクセスの管理に使用されます。デフォルト値は true です。ただし、false(--nofetch)に設定すると、コマンドは依存関係のキャッシュ バージョンを使用します。キャッシュ バージョンが存在しない場合、コマンドは失敗します。

フェッチの制御について詳しくは、フェッチ オプションをご覧ください。

ディレクトリ レイアウト

取得されたリポジトリは、出力ベースのサブディレクトリ external に正規名で保存されます。

次のコマンドを実行すると、正規名 canonical_name のリポジトリの内容を確認できます。

ls $(bazel info output_base)/external/ canonical_name 

REPO.bazel ファイル

REPO.bazel ファイルは、リポジトリを構成するディレクトリ ツリーの最上位の境界をマークするために使用されます。リポジトリ境界ファイルとして機能するために何かを含める必要はありませんが、リポジトリ内のすべてのビルド ターゲットに共通の属性を指定するために使用することもできます。

REPO.bazel ファイルの構文は BUILD ファイルと似ていますが、load ステートメントはサポートされていません。repo() 関数は、BUILD ファイルの package() 関数と同じ引数を取ります。package() はパッケージ内のすべてのビルド ターゲットの共通属性を指定しますが、repo() はリポジトリ内のすべてのビルド ターゲットの共通属性を指定します。

たとえば、次の REPO.bazel ファイルを作成することで、リポジトリ内のすべてのターゲットに共通のライセンスを指定できます。

repo(
    default_package_metadata = ["//:my_license"],
)

以前の WORKSPACE システム

古い Bazel バージョン(9.0 より前)では、WORKSPACE(または WORKSPACE.bazel)ファイルでリポジトリを定義することで、外部依存関係が導入されていました。このファイルは BUILD ファイルと似た構文を持ち、ビルドルールではなくリポジトリ ルールを使用します。

次のスニペットは、WORKSPACE ファイルで http_archive リポジトリルールを使用する例です。

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "foo",
    urls = ["https://example.com/foo.zip"],
    sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96",
)

このスニペットは、正規名が foo のリポジトリを定義します。WORKSPACE システムでは、デフォルトで、リポジトリの正規名が他のすべてのリポジトリに対する表示名にもなります。

WORKSPACE ファイルで使用可能な関数の一覧については、こちらをご覧ください。

WORKSPACE システムの欠点

WORKSPACE システムの導入後、ユーザーから次のような多くの問題点が報告されました。

  • Bazel は依存関係の WORKSPACE ファイルを評価しないため、直接的な依存関係に加えて、すべての推移的依存関係をメイン リポジトリの WORKSPACE ファイルで定義する必要があります。
  • この問題を回避するため、プロジェクトでは「deps.bzl」パターンが採用されています。このパターンでは、複数のリポジトリを定義するマクロを定義し、ユーザーに WORKSPACE ファイルでこのマクロを呼び出すよう求めています。
    • これには独自の問題があります。マクロは他の .bzl ファイルを load できないため、これらのプロジェクトでは、この「deps」マクロで推移的依存関係を定義するか、ユーザーが複数のレイヤード「deps」マクロを呼び出すことでこの問題を回避する必要があります。
    • Bazel は WORKSPACE ファイルを順番に評価します。また、依存関係はバージョン情報なしで URL を使用して http_archive で指定されます。つまり、ダイヤモンド依存関係(ABC に依存し、BC が両方とも D の異なるバージョンに依存する)の場合、バージョン解決を確実に行う方法はありません。

WORKSPACE の欠点により、Bazel 6 と 9 の間で、新しいモジュールベースのシステム(コードネーム「Bzlmod」)がレガシー WORKSPACE システムに徐々に置き換えられました。Bzlmod への移行方法については、Bzlmod 移行ガイドをご覧ください。