Bazel のロックファイル機能を使用すると、プロジェクトに必要なソフトウェア ライブラリまたはパッケージの特定のバージョンまたは依存関係を記録できます。これは、モジュール解決と拡張機能評価の結果を保存することで実現されます。ロックファイルは再現可能なビルドを促進し、一貫性のある開発環境を確保します。また、プロジェクトの依存関係に変更がない場合に Bazel が解決プロセスをスキップできるようにすることで、ビルドの効率を高めます。また、ロックファイルは外部ライブラリの予期しない更新や互換性を破る変更を防ぎ、バグが発生するリスクを軽減することで、安定性を向上させます。
ロックファイルの生成
ロックファイルは、ワークスペース ルートの下に MODULE.bazel.lock
という名前で生成されます。これは、ビルド プロセス中、具体的にはモジュールの解決と拡張機能の評価後に作成または更新されます。ロックファイルには、MODULE ファイル、フラグ、オーバーライドなどの関連情報を含む、プロジェクトの現在の状態が記録されます。重要なのは、ビルドの現在の呼び出しに含まれる依存関係のみが含まれることです。
プロジェクトで依存関係に影響する変更が発生すると、新しい状態を反映するようにロックファイルが自動的に更新されます。これにより、ロックファイルは現在のビルドに必要な特定の依存関係のセットに焦点を当てたままになり、プロジェクトの解決された依存関係を正確に表すことができます。
ロックファイルの利用
ロックファイルは --lockfile_mode
フラグで制御して、プロジェクトの状態がロックファイルと異なる場合の Bazel の動作をカスタマイズできます。使用可能なモードは次のとおりです。
update
(デフォルト): プロジェクトの状態がロックファイルと一致する場合、解決結果はロックファイルからすぐに返されます。それ以外の場合は、解決が実行され、現在の状態を反映するようにロックファイルが更新されます。error
: プロジェクトの状態がロックファイルと一致する場合、解決結果はロックファイルから返されます。それ以外の場合、Bazel はプロジェクトとロックファイルの差異を示すエラーをスローします。このモードは、プロジェクトの依存関係が変更されないようにし、変更があった場合はエラーとして処理する場合に特に便利です。off
: ロックファイルはまったくチェックされません。
ロックファイルのメリット
ロックファイルには次のようなメリットがあり、さまざまな方法で利用できます。
再現可能なビルド。ロックファイルは、ソフトウェア ライブラリの特定のバージョンまたは依存関係をキャプチャすることで、さまざまな環境で、また時間の経過とともにビルドを再現できるようにします。デベロッパーは、プロジェクトの構築時に一貫性のある予測可能な結果に依存できます。
効率的な解決策のスキップ。ロックファイルを使用すると、前回のビルド以降にプロジェクトの依存関係に変更がない場合、Bazel は解決プロセスをスキップできます。これにより、特に解決に時間がかかるシナリオで、ビルドの効率が大幅に向上します。
安定性とリスクの軽減。ロックファイルは、外部ライブラリの予期しない更新や互換性を破る変更を防ぐことで、安定性を維持するのに役立ちます。依存関係を特定のバージョンにロックすることで、互換性のないアップデートやテストされていないアップデートによるバグが発生するリスクを軽減できます。
ロックファイルの内容
ロックファイルには、プロジェクトの状態が変更されたかどうかを判断するために必要なすべての情報が含まれています。また、現在の状態でのプロジェクトのビルド結果も含まれます。ロックファイルは主に次の 2 つの部分で構成されています。
moduleFileHash
、flags
、localOverrideHashes
などのモジュール解像度の入力と、解像度の出力(moduleDepGraph
)。- モジュール拡張機能ごとに、ロックファイルには、
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
マップから削除されます。
このマップの各エントリは、使用されている拡張機能に対応しており、その拡張機能を含むファイルと名前で識別されます。各エントリの対応する値には、その拡張機能に関連付けられた関連情報が含まれています。
transitiveDigest
は、拡張機能の実装とその推移的な .bzl ファイルのダイジェストです。generatedRepoSpecs
は、現在の入力でその拡張機能を実行した結果です。
拡張機能のパフォーマンスに影響を与えるもう 1 つの要因は、その使用状況です。使用状況はロックファイルには保存されませんが、拡張機能の現在の状態とロックファイルの状態を比較する際に考慮されます。
ベスト プラクティス
ロックファイル機能のメリットを最大限に活用するには、次のベスト プラクティスを検討してください。
プロジェクトの依存関係や構成の変更を反映するために、ロックファイルを定期的に更新します。これにより、後続のビルドが最新かつ正確な依存関係のセットに基づいて行われるようになります。
ロックファイルをバージョン管理に含めて、コラボレーションを促進し、すべてのチームメンバーが同じロックファイルにアクセスできるようにして、プロジェクト全体で一貫した開発環境を促進します。
これらのベスト プラクティスに沿って Bazel のロックファイル機能を効果的に活用することで、より効率的で信頼性の高い共同ソフトウェア開発ワークフローを実現できます。