Bazel のモジュール は、複数のバージョンを持つことができる Bazel プロジェクトです。各バージョンは、依存する他のモジュールに関するメタデータを公開します。これは 、Maven の アーティファクト、npm のパッケージ、Go のモジュール、Cargo のクレートなど、他の依存関係管理システムでよく知られている概念に似ています。
モジュールには、リポジトリのルートに MODULE.bazel ファイルが必要です。このファイルはモジュールのマニフェストであり、名前、バージョン、直接的な依存関係のリストなどの情報が宣言されています。基本的な例を次に示します。
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")
`
MODULE.bazel` ファイルで使用できるディレクティブの完全なリストをご覧ください。
モジュールの解決を行うために、Bazel はまずルート モジュールの
MODULE.bazel ファイルを読み取り、依存関係グラフ全体が検出されるまで、依存関係の
MODULE.bazel ファイルを Bazel レジストリ に繰り返しリクエストします。
デフォルトでは、Bazel は使用する各モジュールの 1 つのバージョンを選択します 。Bazel は各モジュールをリポジトリで表し、レジストリに再度問い合わせて、各リポジトリの定義方法を確認します。
バージョン形式
Bazel には多様なエコシステムがあり、プロジェクトではさまざまなバージョニング スキームが使用されています。圧倒的に人気があるのは SemVer ですが、Abseil のように異なるスキームを使用する著名なプロジェクトもあります。Abseil のバージョンは日付ベースです(例: 20210324.2).
このため、Bazel は SemVer 仕様のより緩やかなバージョンを採用しています。違いは次のとおりです。
- SemVer では、バージョンの「リリース」部分は
MAJOR.MINOR.PATCHの 3 つのセグメントで構成する必要があります。Bazel では、この要件が緩和され、任意の数のセグメントが許可されます。 - SemVer では、「リリース」部分の各セグメントは数字のみで構成する必要があります。 Bazel では、文字も許可されるように緩和され、比較セマンティクスは「プレリリース」部分の「識別子」と一致します。
- また、メジャー バージョン、マイナー バージョン、パッチ バージョンの増加のセマンティクスは適用されません。
有効な SemVer バージョンは、有効な Bazel モジュール バージョンです。また、2 つの
SemVer バージョン a と b は、Bazel モジュール バージョンとして比較した場合と同じ場合にのみ a < b と比較されます。
最後に、モジュールのバージョニングの詳細については、よくある質問MODULE.bazel
をご覧ください。
バージョンの選択
バージョニングされた依存関係管理スペースの定番であるダイヤモンド依存関係の問題について考えてみましょう。次のような依存関係グラフがあるとします。
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
使用する D のバージョンはどれですか?この問題を解決するために、Bazel は
最小バージョン選択
(MVS)アルゴリズムを Go モジュール システムで導入しました。MVS は、モジュールの新しいバージョンはすべて下位互換性があることを前提として、依存関係(この例では D 1.1)で指定された最も高いバージョンを選択します。D 1.1 は要件を満たすことができる最も古いバージョンであるため、「最小」と呼ばれます。D 1.2 以降が存在する場合でも、選択されません。MVS を使用すると、
忠実度が高く再現可能なバージョンの選択プロセスが作成されます。
ヤンクされたバージョン
レジストリは、回避する必要があるバージョン(セキュリティの脆弱性など)をヤンクされたバージョンとして宣言できます。 Bazel は、モジュールのヤンクされたバージョンを選択するとエラーをスローします。このエラーを修正するには、新しい
ヤンクされていないバージョンにアップグレードするか、
--allow_yanked_versions
フラグを使用してヤンクされたバージョンを明示的に許可します。
オーバーライド
MODULE.bazel ファイルでオーバーライドを指定して、Bazel モジュールの解決の動作を変更します。有効になるのはルート モジュールのオーバーライドのみです。モジュールが依存関係として使用されている場合、そのオーバーライドは無視されます。
各オーバーライドは特定のモジュール名に対して指定され、依存関係グラフ内のすべてのバージョンに影響します。有効になるのはルート モジュールのオーバーライドのみですが、ルート モジュールが直接依存しない推移的な依存関係に対してオーバーライドできます。
単一バージョンのオーバーライド
The single_version_override
には複数の目的があります。
version属性を使用すると、依存関係グラフでリクエストされた依存関係のバージョンに関係なく、依存関係を特定のバージョンに固定できます。registry属性を使用すると、通常の registry selection プロセスに従うのではなく、この依存関係を a specific registry から取得するように強制できます。patch*属性を使用すると、ダウンロードしたモジュールに適用するパッチのセットを指定できます。
これらの属性はすべて省略可能で、組み合わせて使用できます。
複数バージョンのオーバーライド
multiple_version_override
を指定すると、解決された依存関係グラフで同じモジュールの複数のバージョンを共存させることができます。
依存関係グラフに同じモジュールの複数のバージョンが残っている場合、Bazel は依存関係ごとに最も近い上位の許可されたバージョンを選択します。
たとえば、解決前の依存関係グラフにバージョン 1.1、1.3、1.5、1.7、2.0 が存在する場合:
1.3、1.7、2.0を許可する複数バージョンのオーバーライドにより、1.1が1.3にアップグレードされ、1.5が1.7にアップグレードされ、他のバージョンは変更されません。1.9と2.0を許可する複数バージョンのオーバーライドは、解決前の依存関係グラフに1.9が存在しないため、エラーになります。
また、単一バージョンのオーバーライドと同様に、registry 属性を使用してレジストリをオーバーライドすることもできます。
非レジストリのオーバーライド
非レジストリのオーバーライドは、バージョン解決からモジュールを完全に削除します。Bazel は、これらの MODULE.bazel ファイルをレジストリからではなく、リポジトリ自体からリクエストします。
Bazel は、次の非レジストリのオーバーライドをサポートしています。
モジュールが非レジストリのオーバーライドでオーバーライドされている場合、ソース アーカイブ MODULE.bazel にバージョン値を設定すると、デメリットが生じる可能性があります。詳細については、
よくある質問をご覧ください。MODULE.bazel
Bazel モジュールを表さないリポジトリを定義する
bazel_dep を使用すると、他の Bazel モジュールを表すリポジトリを定義できます。Bazel モジュールを表さないリポジトリを定義する必要がある場合があります。たとえば、データとして読み取るプレーン JSON ファイルを含むリポジトリなどです。
この場合、use_repo_ruleディレクティブを使用して、リポジトリルールを呼び出すことでリポジトリを直接定義できます。このリポジトリは、定義されているモジュールでのみ表示されます。
内部的には、モジュール拡張機能と同じメカニズムを使用して実装されます。これにより、より柔軟にリポジトリを定義できます。
リポジトリ名と厳密な依存関係
モジュールを直接依存関係にバックアップするリポジトリの表示名は、
repo_name 属性が bazel_dep
ディレクティブで指定されていない限り、デフォルトでモジュール名になります。つまり、モジュールは直接的な依存関係のみを検出できます。これにより、推移的な依存関係の変更による意図しない破損を防ぐことができます。
モジュールをバックアップするリポジトリの正規名は、依存関係グラフ全体にモジュールの複数のバージョンがあるかどうかに応じて、module_name+version(例: bazel_skylib+1.0.3)またはmodule_name+(例: bazel_features+)です(multiple_version_overrideを参照)。正規名の形式は、依存すべき API ではなく、いつでも変更される可能性があります。正規名をハードコードする代わりに、サポートされている方法で Bazel から直接取得します。
- BUILD ファイルと
.bzlファイルでは、リポジトリの表示名で指定されたラベル文字列から構築されたLabelインスタンスでLabel.repo_nameを使用します(例:Label("@bazel_skylib").repo_name)。 - 実行ファイルを参照する場合は、
$(rlocationpath ...)または@bazel_tools//tools/{bash,cpp,java}/runfilesの実行ファイル ライブラリのいずれかを使用します。ルールセットrules_fooの場合は、@rules_foo//foo/runfilesを使用します。 - IDE や言語
サーバーなどの外部ツールから Bazel を操作する場合は、
bazel mod dump_repo_mappingコマンドを使用して、指定されたリポジトリのセットの表示名から正規名へのマッピングを取得します。
モジュール拡張機能を使用すると、モジュールの可視スコープに追加のリポジトリを導入することもできます 。