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": {
      "transitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
      "generatedRepoSpecs": {
        "hello": {
          "bzlFile": "@@//:extension.bzl",
          ...
        }
      }
    }
  }
}

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

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

フラグ

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

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

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

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

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

モジュール拡張機能

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

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

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

拡張機能の結果に影響する可能性のある追加の要因は、その使用状況です。 ロックファイルには保存されませんが、拡張機能の現在の状態とロックファイルの状態を比較する際に使用状況が考慮されます。

ベスト プラクティス

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

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

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

これらのベスト プラクティスに従うことで、Bazel のロックファイル 機能を効果的に活用し、より効率的で信頼性の高い、共同作業に適した ソフトウェア開発ワークフローを実現できます。