Bzlmod で外部依存関係を管理する

<ph type="x-smartling-placeholder"></ph> 問題を報告する ソースを表示 夜間 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bzlmod は、新しい外部依存関係システムのコードネームです。 Bazel 5.0 で導入されました。これは、クラウド コンピューティング モデルにおける 段階的に修正することができなかった古いシステム。詳しくは、 元の設計書の「問題の説明」セクション をご覧ください。

Bazel 5.0 では、Bzlmod はデフォルトで有効になっていません。フラグ 以下を取得するには、--experimental_enable_bzlmod を指定する必要があります。 できます。フラグ名が示すように、この機能は現在試験運用版です。 API と動作は、機能が正式にリリースされるまで変更される可能性があります。

プロジェクトを Bzlmod に移行するには、Bzlmod 移行ガイドに沿って進めてください。 Bzlmod の使用例は、examples リポジトリにも記載されています。

Bazel モジュール

従来の WORKSPACE ベースの外部依存関係システムは、 リポジトリ ルール(またはリポジトリ ルール)によって作成されるリポジトリ(またはリポジトリ)。 リポジトリは新しいシステムでも重要なコンセプトですが、モジュールは 中心的な役割を担います

モジュールは基本的に、それぞれに複数のバージョンを持つことができる Bazel プロジェクトです。 依存関係にある他のモジュールに関するメタデータを公開します。これは、 これは、他の依存関係管理システムにおけるよく知られた概念によく似ています。 artifact、npm package、Cargo クレート、Go モジュールなど

モジュールは、単に nameversion のペアを使用して依存関係を指定します。 具体的な URL の代わりに、WORKSPACE を使用します。次に、依存関係が UDM イベントで Bazel レジストリデフォルトでは Bazel Central Registry。ワークスペースでは リポジトリに変換されます。

MODULE.bazel

すべてのモジュールのすべてのバージョンに、モジュール名を宣言する 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 ファイルは、ワークスペース ディレクトリのルートに配置する必要があります。 (WORKSPACE ファイルの隣)。WORKSPACE ファイルとは異なり、 推移的依存関係を指定します。代わりに、1 対 1 の 直接依存関係にあり、依存関係の MODULE.bazel ファイルは、 推移的依存関係を自動的に検出できます。

MODULE.bazel ファイルは BUILD ファイルと類似しており、 です。また、load ステートメントも禁止されています。ディレクティブ サポートされている MODULE.bazel ファイルは次のとおりです。

バージョン形式

Bazel には多様なエコシステムがあり、プロジェクトではさまざまなバージョニング スキームが使用されています。「 最も人気があるのは SemVer ですが、 さまざまなスキームを使用する著名なプロジェクトも Abseil バージョンは日付ベースです(例: 20210324.2)。

そのため、Bzlmod では SemVer 仕様のより緩和されたバージョンを採用しています。「 次のような違いがあります。

  • SemVer では、「リリース」3 つの部分で構成されている必要があります。 セグメント: MAJOR.MINOR.PATCH。Bazel ではこの要件が緩和されているため、 いくつでもセグメントが許可されます
  • SemVer では、「リリース」セクションの各セグメントは数値のみを使用できます。 Bazel ではこれを緩めて文字も許容しています。 「identifiers」と一致するようにします。「プレリリース版」をなります。
  • さらに、メジャー バージョン、マイナー バージョン、パッチ バージョンの増加のセマンティクスは、 適用されます。(ただし、Terraform の互換性レベルを 下位互換性の表記に関する詳細)。

有効な SemVer バージョンとは、有効な Bazel モジュール バージョンのことです。さらに SemVer バージョン ab は、次の場合に同じことが当てはまる場合に a < b を比較します。 Bazel モジュールバージョンとの比較です。

バージョンの解決

ダイヤモンドの依存関係の問題は、バージョニングされた依存関係の重要な部分 管理スペースになります。次のような依存関係グラフがあるとします。

       A 1.0
      /     \
   B 1.0    C 1.1
     |        |
   D 1.0    D 1.1

どのバージョンの D を使用すればよいですか。この問題を解決するために、Bzlmod は 最小バージョンの選択 (MVS)アルゴリズムが Go モジュール システムに導入されました。MVS では、 下位互換性があるため、単に最も古いバージョンを (この例では D 1.1)。「ミニマル」と呼ばれます D 1.1 が要件を満たす最小バージョンだからです。 D 1.2 以降が存在しても選択されません。この方法には バージョンが「高忠実度」かつ「再現性」であること。

バージョン解決はレジストリではなく、マシン上でローカルに行われます。

互換性レベル

後方互換性に関する MVS の想定は、 モジュールの後方互換性のないバージョンを別のモジュールとして扱います。 SemVer に関しては、A 1.x と A 2.x は別個のモジュールと見なされます。 解決された依存関係グラフ内に共存できますそしてこれは メジャー バージョンは、このアプリケーションのパッケージ パスにエンコードされているため、 コンパイル時もリンク時も競合しません

Bazel では、このような保証はありません。したがって、「主要な」指標を表す方法が必要です。 バージョン」下位互換性のないバージョンを検出します。この番号 「互換性レベル」と呼ばれ、このモジュールの その module() ディレクティブを指定します。この情報がわかれば、エラーをスローできます。 同じモジュールのバージョン間で互換性の異なる 解決された依存関係グラフ内に存在します。

リポジトリ名

Bazel では、すべての外部依存関係にリポジトリ名があります。ときには、 異なるリポジトリ名(たとえば、 @io_bazel_skylib@bazel_skylib の平均 Bazel skylib)または リポジトリ名が、異なるプロジェクトのさまざまな依存関係に使用される場合があります。

Bzlmod では、リポジトリは Bazel モジュールで生成でき、 モジュール拡張機能。リポジトリ名の競合を解決するには リポジトリのマッピングを採用 確認しました。次の 2 つの重要なコンセプトがあります。

  • 正規リポジトリ名: 各リポジトリにグローバルに一意の名前 できます。これが、リポジトリが存在するディレクトリ名になります。
    次のように構成されます(警告: 正規名の形式は (信頼できる API ではありませんが、随時変更される可能性あり)

    • Bazel モジュール リポジトリの場合: module_name~version
      @bazel_skylib~1.0.3)
    • モジュール拡張リポジトリの場合: module_name~version~extension_name~repo_name
      @rules_cc~0.0.1~cc_configure~local_config_cc)
  • 明示的なリポジトリ名: BUILD と リポジトリ内の .bzl ファイル。同じ依存関係でも、見かけ上 おすすめします。
    次のように決定されます。

    • Bazel モジュール リポジトリの場合: module_name( default、または repo_name 属性で指定された名前、 bazel_dep
    • モジュール拡張リポジトリの場合: を介して導入されたリポジトリ名 use_repo

すべてのリポジトリには、その直接的な依存関係のリポジトリ マッピング辞書があります。 これは、見た目のリポジトリ名から正規のリポジトリ名へのマップです。 リポジトリ名を解決するために、リポジトリ マッピングを使用します。 指定します。なお、正規のリポジトリ名と、 明らかなリポジトリ名の使用は、MODULE.bazel を解析することで検出できます。 そのため、競合アプリケーションに影響を与えることなく、簡単に競合を検出して解決できます。 依存関係が存在します。

厳格な依存関係

新しい依存関係指定形式を使用すると、より厳密なチェックを実行できます。イン 具体的には、モジュールはそこから作成されたリポジトリのみを サポートしています。これにより、偶発的なデバッグやデバッグが困難な破損を防ぐことができます。 変化があったときです

厳密な依存関係は、次に基づいて実装されます。 リポジトリ マッピング。基本的に、 各リポジトリのリポジトリ マッピングに、すべての直接依存関係、 他のリポジトリは表示されません。各リポジトリに表示される依存関係は、 次のように決定されます。

  • Bazel モジュール リポジトリでは、MODULE.bazel ファイルに導入されたすべてのリポジトリを確認できます bazel_dep 経由、および use_repo
  • モジュール拡張リポジトリは、モジュール外に存在する 拡張機能と、同じモジュールによって生成された他のすべてのリポジトリ あります。

レジストリ

bzlmod が Bazel から依存関係の情報をリクエストして依存関係を検出する レジストリです。Bazel レジストリは、単なる Bazel モジュールのデータベースです。唯一の サポートされているレジストリの形式は、インデックス レジストリです。これは、 ローカル ディレクトリや、特定の形式に従った静的 HTTP サーバーです。 将来的には、単一モジュール レジストリのサポートを追加する予定です。 プロジェクトのソースと履歴を含む Git リポジトリ。

インデックス レジストリ

インデックス レジストリは、ローカル ディレクトリまたは静的 HTTP サーバーで、 モジュールのリストに関する情報が表示されます。これには、モジュールのホームページ、管理者、 各バージョンの MODULE.bazel ファイルと、各バージョンのソースの取得方法 できます。特に、ソース アーカイブ自体を提供する必要はありません

インデックス レジストリは、次の形式に従う必要があります。

  • /bazel_registry.json: 次のようなレジストリのメタデータを含む JSON ファイル。 <ph type="x-smartling-placeholder">
      </ph>
    • mirrors。ソース アーカイブに使用するミラーのリストを指定します。
    • module_base_path: モジュールのベースパスを指定します。 source.json ファイルに local_repository 型を指定します。
  • /modules: このプロジェクト内の各モジュールのサブディレクトリを含むディレクトリ されます。
  • /modules/$MODULE: 各バージョンのサブディレクトリを含むディレクトリ 次のファイルと、 <ph type="x-smartling-placeholder">
      </ph>
    • metadata.json: モジュールに関する情報を含む JSON ファイル。 次のフィールドがあります <ph type="x-smartling-placeholder">
        </ph>
      • homepage: プロジェクトのホームページの URL。
      • maintainers: JSON オブジェクトのリスト。それぞれが対応する レジストリ内のモジュールのメンテナンス担当者の情報。 これらは、必ずしも書籍の作成者とは できます。
      • versions: このモジュールのすべてのバージョンのリスト。 作成されます。
      • yanked_versions: このモジュールのヤンクされたバージョンのリスト。この 現時点では何もする必要はありませんが、将来的には スキップするかエラーになります
  • /modules/$MODULE/$VERSION: 次のファイルを含むディレクトリ。 <ph type="x-smartling-placeholder">
      </ph>
    • MODULE.bazel: このモジュール バージョンの MODULE.bazel ファイル。
    • source.json: 取得方法に関する情報を含む JSON ファイル。 ソースを指定します。
      • デフォルトのタイプは「archive」です。次のフィールドがあります <ph type="x-smartling-placeholder">
          </ph>
        • url: ソース アーカイブの URL。
        • integrity: サブリソースの整合性 チェックサムのチェックサムです。
        • strip_prefix: .tfvars ファイルを抽出する際に削除するディレクトリ接頭辞 ソース アーカイブです。
        • patches: 文字列のリスト。各文字列は、パッチファイルの名前を指定します。 適用されます。パッチファイルは /modules/$MODULE/$VERSION/patches ディレクトリ。
        • patch_strip: Unix パッチの --strip 引数と同じです。
      • 次のフィールドでローカルパスを使用するように型を変更できます。 <ph type="x-smartling-placeholder">
          </ph>
        • type: local_path
        • path: リポジトリのローカルパス。次のように計算されます。 <ph type="x-smartling-placeholder">
            </ph>
          • パスが絶対パスの場合は、そのまま使用されます。
          • パスが相対パスで、module_base_path が絶対パスの場合: パスは <module_base_path>/<path> に解決されます。
          • パスと module_base_path の両方が相対パスの場合、パスは <registry_path>/<module_base_path>/<path> に解決。 レジストリはローカルにホストし、--registry=file://<registry_path> が使用する必要があります。 そうしないと、Bazel はエラーをスローします。
    • patches/: パッチファイルを含むオプションのディレクトリ。source.json に「archive」がある場合にのみ使用されます。あります。

Bazel Central Registry

Bazel Central Registry(BCR)は、次の場所にあるインデックス レジストリです。 bcr.bazel.build.内容 GitHub リポジトリを基盤としています bazelbuild/bazel-central-registry

BCR は Bazel コミュニティによって管理されています。コントリビューターは pull リクエスト。詳しくは、 Bazel Central Registry ポリシーとプロシージャ

BCR では、通常のインデックス レジストリの形式に従うだけでなく、 モジュール バージョンごとの presubmit.yml ファイル (/modules/$MODULE/$VERSION/presubmit.yml)。このファイルでは、 ビルドおよびテスト ターゲットを使用して、このリソースの有効性をサニティ チェックできます。 BCR の CI パイプラインで使用され、相互運用性を確保するために BCR 内のモジュール間で行われます。

レジストリの選択

繰り返し可能な Bazel フラグ --registry を使用して、 モジュールをリクエストするためのレジストリが決まるため、 サードパーティまたは内部レジストリから分離します。以前のレジストリは 優先されます。便宜上、--registry フラグのリストを プロジェクトの .bazelrc ファイル。

モジュール拡張機能

モジュール拡張機能を使用すると、入力データを読み取ってモジュール システムを拡張できる 解決に必要なロジックを実行して、依存関係グラフ全体の 最後に、Repo ルールを呼び出してリポジトリを作成します。似ている 現在の WORKSPACE マクロと同等の働きをしますが、より適しているのは 推移的依存関係です。

モジュールの拡張機能は、Repo ルールや .bzl ファイルで定義され、 WORKSPACE マクロ。直接呼び出されることはありません。モジュールごとに 拡張機能が読み取るタグと呼ばれるデータを指定します。モジュールの バージョンの解決が完了すると、モジュール拡張機能が実行されます。各拡張機能は モジュールの解決後 1 回(まだビルドが実際に行われる前に) 属しているすべてのタグを、依存関係グラフ全体で読み取ることができます。

          [ A 1.1                ]
          [   * maven.dep(X 2.1) ]
          [   * maven.pom(...)   ]
              /              \
   bazel_dep /                \ bazel_dep
            /                  \
[ B 1.2                ]     [ C 1.0                ]
[   * maven.dep(X 1.2) ]     [   * maven.dep(X 2.1) ]
[   * maven.dep(Y 1.3) ]     [   * cargo.dep(P 1.1) ]
            \                  /
   bazel_dep \                / bazel_dep
              \              /
          [ D 1.4                ]
          [   * maven.dep(Z 1.4) ]
          [   * cargo.dep(Q 1.1) ]

上記の依存関係グラフの例では、A 1.1B 1.2 などが Bazel モジュールです。 それぞれ MODULE.bazel ファイルと考えることができます。各モジュールで特定の変数の モジュール拡張用のタグ拡張子「maven」に指定されているものもあります "cargo" と指定されたものもあれば、この依存関係グラフがファイナライズされると( たとえば、B 1.2 が実際には D 1.3bazel_dep を持っていても、 C による D 1.4)、拡張機能「maven」実行されると、すべてのデータが maven.* タグ。その中の情報を使用して、作成するリポジトリを決定します。 「cargo」も同様で、あります。

拡張機能の使用状況

拡張機能は Bazel モジュール自体でホストされるため、 まず、そのモジュールに bazel_dep を追加してから use_extension ビルトイン 関数でスコープに含めます。例として、BigQuery の MODULE.bazel ファイル。架空の「maven」を使用します。拡張子が rules_jvm_external モジュール:

bazel_dep(name = "rules_jvm_external", version = "1.0")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

拡張機能をスコープに配置したら、ドット構文を使用して タグを指定しますタグは、 対応するタグクラス拡張機能の定義を参照) をご覧ください)。maven.dep タグと maven.pom タグを指定する例を次に示します。

maven.dep(coord="org.junit:junit:3.0")
maven.dep(coord="com.google.guava:guava:1.2")
maven.pom(pom_xml="//:pom.xml")

モジュールで使用するリポジトリが拡張機能によって生成された場合は、 use_repo ディレクティブで、 できます。これは、厳格な deps 条件を満たし、ローカル リポジトリ名を回避するためです。 あります。

use_repo(
    maven,
    "org_junit_junit",
    guava="com_google_guava_guava",
)

拡張機能によって生成されたリポジトリは、拡張機能の API の一部であるため、 指定した場合、「maven」が別の Pod に 「org_junit_junit」、もう一つは「com_google_guava_guava」という名前のリポジトリです。あり use_repo のように、モジュールの範囲内で名前を変更することもできます。たとえば、 「guava」見てみましょう。

広告表示オプションの定義

モジュール拡張は、Repo ルールと同様に、 module_extension 関数。 どちらも実装関数を備えています。一方、Repo ルールには多数の モジュール拡張機能には、 tag_class。各値には、 あります。タグクラスは、この API が使用するタグのスキーマを定義します。 あります。架空の「maven」の例を続けます。上記の拡張機能:

# @rules_jvm_external//:extensions.bzl
maven_dep = tag_class(attrs = {"coord": attr.string()})
maven_pom = tag_class(attrs = {"pom_xml": attr.label()})
maven = module_extension(
    implementation=_maven_impl,
    tag_classes={"dep": maven_dep, "pom": maven_pom},
)

これらの宣言により、maven.dep タグと maven.pom タグに 上で定義した属性スキーマを使用します。

実装関数は WORKSPACE マクロと似ていますが、 module_ctx オブジェクトを取得し、 すべての関連タグにアクセスできます。実装 関数が Repo ルールを呼び出して、リポジトリを生成します。

# @rules_jvm_external//:extensions.bzl
load("//:repo_rules.bzl", "maven_single_jar")
def _maven_impl(ctx):
  coords = []
  for mod in ctx.modules:
    coords += [dep.coord for dep in mod.tags.dep]
  output = ctx.execute(["coursier", "resolve", coords])  # hypothetical call
  repo_attrs = process_coursier(output)
  [maven_single_jar(**attrs) for attrs in repo_attrs]

上記の例では、依存関係グラフのすべてのモジュールを調べています。 (ctx.modules)。それぞれ tags フィールドを持つ bazel_module オブジェクト モジュールのすべての maven.* タグを公開する。次に、CLI ユーティリティを呼び出します。 Coursier に Maven に連絡して解決を依頼します。最後に、解像度を使用します。 架空の maven_single_jar を使用して、いくつかのリポジトリを作成します。 追加します。