Bazel 中的锁文件功能支持记录项目所需软件库或软件包的特定版本或依赖项。它通过存储模块解析和扩展程序评估的结果来实现这一点。锁文件有助于实现可重现的 build,确保开发环境保持一致。此外,它还允许 Bazel 在项目依赖项没有任何更改时跳过解析流程,从而提高构建效率。此外,锁文件还可以通过防止外部库中发生意外更新或破坏性更改来提高稳定性,从而降低引入 bug 的风险。
锁文件生成
锁文件会在工作区根目录下生成,名称为 MODULE.bazel.lock
。它会在构建过程中创建或更新,尤其是在模块解析和扩展程序评估之后。锁文件会捕获项目的当前状态,包括 MODULE 文件、标志、替换项和其他相关信息。重要的是,它仅包含当前 build 调用中包含的依赖项。
当项目发生影响其依赖项的更改时,锁定文件会自动更新以反映新状态。这样可确保锁定文件始终专注于当前 build 所需的一组特定依赖项,从而准确表示项目的已解析依赖项。
锁文件用法
锁文件可以通过标志 --lockfile_mode
进行控制,以便在项目状态与锁文件不同时自定义 Bazel 的行为。可用的模式包括:
update
(默认):如果项目状态与锁定文件相符,则锁定文件会立即返回解决方案结果。否则,系统会执行解析,并更新锁定文件以反映当前状态。error
:如果项目状态与锁定文件匹配,则从锁定文件返回解决方案结果。否则,Bazel 会抛出一个错误,指明项目和锁定文件之间的差异。如果您希望确保项目的依赖项保持不变,并将任何差异视为错误,此模式特别有用。off
:系统根本不会检查锁定文件。
锁文件优势
锁文件具有多种优势,可通过多种方式使用:
可重现的 build。通过捕获软件库的特定版本或依赖项,锁定文件可确保 build 在不同环境中和随着时间的推移可重现。开发者在构建项目时可以依赖一致且可预测的结果。
高效跳过分辨率。借助锁定文件,如果项目依赖项自上次构建以来没有任何更改,Bazel 便可以跳过解析过程。这会显著提高构建效率,尤其是在解决问题可能需要花费大量时间的情况下。
稳定性和风险降低。锁文件有助于防止外部库发生意外更新或破坏性更改,从而保持稳定性。通过将依赖项锁定到特定版本,可以降低因不兼容或未经测试的更新而引入 bug 的风险。
锁文件内容
锁文件包含确定项目状态是否已更改所需的所有信息。它还包含在当前状态下构建项目的结果。锁文件由两个主要部分组成:
- 模块解析的输入(例如
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
是使用当前输入运行该扩展程序的结果。
可能影响扩展程序结果的另一个因素是其使用情况。虽然这些用量并未存储在锁定文件中,但在将扩展程序的当前状态与锁定文件中的状态进行比较时,系统会将这些用量考虑在内。
最佳做法
为了最大限度地发挥锁文件功能的好处,请考虑以下最佳实践:
定期更新锁定文件,以反映项目依赖项或配置的更改。这样可确保后续 build 基于最新且准确的一组依赖项。
将锁定文件添加到版本控制中,以便于协作并确保所有团队成员都可以访问同一锁定文件,从而促进整个项目中开发环境的一致性。
遵循这些最佳实践,您可以有效利用 Bazel 中的锁文件功能,从而实现更高效、更可靠且更具协作性的软件开发工作流。