Bazel ロックファイル

問題を報告 ソースを表示

Bazel のロックファイル機能を使用すると、プロジェクトに必要なソフトウェア ライブラリやパッケージの特定のバージョンや依存関係を記録できます。これは、モジュールの解決と拡張機能の評価の結果を保存することで実現されます。ロックファイルは再現可能なビルドを促進し、一貫した開発環境を保証します。さらに、プロジェクトの依存関係に変更がない場合、Bazel が解決プロセスをスキップできるようにすることで、ビルド効率が向上します。さらに、ロックファイルは、外部ライブラリの予期しない更新や互換性を破る変更を防止して安定性を向上させ、バグが発生するリスクを軽減します。

ロックファイルの生成

ロックファイルはワークスペースのルートに MODULE.bazel.lock という名前で生成されます。ビルドプロセス中、特にモジュールの解決と拡張機能の評価の後で作成または更新されます。ロックファイルは、MODULE ファイル、フラグ、オーバーライド、その他の関連情報など、プロジェクトの現在の状態をキャプチャします。重要なのは、現在のビルド呼び出しに含まれる依存関係のみが含まれることです。

依存関係に影響する変更がプロジェクトで発生すると、新しい状態を反映するようにロックファイルが自動的に更新されます。これにより、ロックファイルが現在のビルドに必要な特定の依存関係セットにフォーカスされ、プロジェクトの解決済み依存関係を正確に表現できます。

ロックファイルの使用状況

ロックファイルは --lockfile_mode フラグで制御して、プロジェクトの状態がロックファイルと異なる場合の Bazel の動作をカスタマイズできます。使用可能なモードは次のとおりです。

  • update(デフォルト): プロジェクトの状態がロックファイルと一致する場合、解決結果がロックファイルからすぐに返されます。それ以外の場合は、解決が実行され、現在の状態を反映するようにロックファイルが更新されます。
  • error: プロジェクトの状態がロックファイルと一致する場合、ロックファイルから解決結果が返されます。そうしないと、Bazel はプロジェクトとロックファイルの間の差異を示すエラーをスローします。このモードは、プロジェクトの依存関係を変更せずに、相違点をエラーとして処理する場合に特に便利です。
  • off: ロックファイルはまったくチェックされません。

ロックファイルの利点

ロックファイルにはいくつかの利点があり、さまざまな方法で利用できます。

  • 再現可能なビルド。ロックファイルでは、ソフトウェア ライブラリの特定のバージョンや依存関係をキャプチャすることで、さまざまな環境や時間の経過に伴ってビルドを再現できます。デベロッパーは、プロジェクトをビルドするときに、一貫性があり予測可能な結果を得ることができます。

  • 効率的に解決をスキップ。ロックファイルにより、最後のビルド以降にプロジェクトの依存関係に変更がない場合、Bazel は解決プロセスをスキップできます。これにより、特に解決に時間がかかるケースでは、ビルドの効率が大幅に向上します。

  • 安定性とリスクの軽減。ロックファイルは、外部ライブラリでの予期しない更新や互換性を破る変更を防止することで安定性を維持します。依存関係を特定のバージョンにロックすることで、互換性のない更新やテストされていない更新が原因でバグが発生するリスクが軽減されます。

ロックファイルの内容

ロックファイルには、プロジェクトの状態が変更されたかどうかを判断するために必要なすべての情報が含まれています。また、現在の状態でプロジェクトをビルドした結果も含まれます。ロックファイルは主に次の 2 つの部分で構成されます。

  1. モジュール解像度の入力(moduleFileHashflagslocalOverrideHashes など)と、解像度の出力(moduleDepGraph
  2. ロックファイルには、モジュール拡張機能ごとに、それに影響する入力(transitiveDigest)と、その拡張機能の実行による出力(generatedRepoSpecs)が含まれます。

以下に、ロックファイルの構造と各セクションの説明の例を示します。

{
  "lockFileVersion": 1,
  "moduleFileHash": "b0f47b98a67ee15f9.......8dff8721c66b721e370",
  "flags": {
    "cmdRegistries": [
      "https://bcr.bazel.build/"
    ],
    "cmdModuleOverrides": {},
    "allowedYankedVersions": [],
    "envVarAllowedYankedVersions": "",
    "ignoreDevDependency": false,
    "directDependenciesMode": "WARNING",
    "compatibilityMode": "ERROR"
  },
  "localOverrideHashes": {
    "bazel_tools": "b5ae1fa37632140aff8.......15c6fe84a1231d6af9"
  },
  "moduleDepGraph": {
    "<root>": {
      "name": "",
      "version": "",
      "executionPlatformsToRegister": [],
      "toolchainsToRegister": [],
      "extensionUsages": [
        {
          "extensionBzlFile": "extension.bzl",
          "extensionName": "lockfile_ext"
        }
      ],
      ...
    }
  },
  "moduleExtensions": {
    "//:extension.bzl%lockfile_ext": {
      "general": {
        "transitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    },
    "//:extension.bzl%lockfile_ext2": {
      "os:macos": {
        "transitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      },
      "os:linux": {
        "transitiveDigest": "eWDzxG/aLsyY3Ubrto....+Jp4maQvEPxn0pLK=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    }
  }
}

モジュールファイルハッシュ

moduleFileHash は、MODULE.bazel ファイルの内容のハッシュを表します。このファイルに変更が発生すると、ハッシュ値は異なります。

フラグ

Flags オブジェクトには、解決結果に影響する可能性があるすべてのフラグが格納されます。

ローカルオーバーライドハッシュ

ルート モジュールに local_path_overrides が含まれている場合、このセクションは MODULE.bazel ファイルのハッシュをローカル リポジトリに保存します。この依存関係に対する変更を追跡できます

モジュールの依存関係グラフ

moduleDepGraph は、上記の入力を使用した解決プロセスの結果を表します。これにより、プロジェクトの実行に必要なすべてのモジュールの依存関係グラフが形成されます。

モジュール拡張機能

moduleExtensions セクションは、現在の呼び出しで使用されている拡張機能または以前に呼び出された拡張機能のみを含むマップで、使用されなくなった拡張機能は除外します。つまり、依存関係グラフ全体で使用されなくなった拡張機能は、moduleExtensions マップから削除されます。

拡張機能がオペレーティング システムやアーキテクチャ タイプに依存しない場合、このセクションには 1 つの「一般」エントリのみが表示されます。それ以外の場合は、OS、アーキテクチャ、またはその両方に基づいた名前の複数のエントリが含まれ、各エントリはそれらの詳細に関する拡張機能の評価結果に対応します。

拡張機能マップの各エントリは、使用されている拡張機能に対応し、含まれるファイルと名前で識別されます。各エントリの対応する値には、その拡張機能に関連付けられた関連情報が含まれています。

  1. transitiveDigest: 拡張機能実装とその推移的な .bzl ファイルのダイジェスト。
  2. generatedRepoSpecs は、現在の入力で拡張機能を実行した結果です。

拡張機能の結果に影響を与えるもう 1 つの要因は、使用状況です。使用状況はロックファイルに保存されませんが、拡張機能の現在の状態とロックファイル内の状態を比較する際に考慮されます。

ベスト プラクティス

ロックファイル機能を最大限に活用するには、次のベスト プラクティスを検討してください。

  • ロックファイルを定期的に更新して、プロジェクトの依存関係や構成の変更を反映します。これにより、それ以降のビルドは、最新かつ正確な依存関係のセットに基づいて行われます。

  • コラボレーションを容易にし、すべてのチームメンバーが同じロックファイルにアクセスできるように、バージョン管理にロックファイルを含めると、プロジェクト全体で一貫した開発環境が促進されます。

  • bazelisk を使用して Bazel を実行し、ロックファイルに対応する Bazel バージョンを指定する .bazelversion ファイルをバージョン管理に含めます。Bazel 自体はビルドの依存関係であるため、ロックファイルは Bazel バージョンに固有のものであり、下位互換性のある Bazel リリース間でも変更されます。bazelisk を使用すると、すべてのデベロッパーがロックファイルと一致する Bazel バージョンを使用するようになります。

以下のベスト プラクティスに従うことで、Bazel のロックファイル機能を効果的に活用でき、より効率的で信頼性が高く、コラボレーションに優れたソフトウェア開発ワークフローを実現できます。