A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
应使用哪个版本的 D?为了解决这个问题,Bazel 使用 Go 模块系统中引入的最小版本选择 (MVS) 算法。MVS 假设模块的所有新版本都向后兼容,因此会选择任何依赖项(在本例中为 D 1.1)指定的最高版本。之所以称为“最小”,是因为 D 1.1 是满足我们要求的最早版本 - 即使存在 D 1.2 或更新版本,我们也不会选择它们。使用 MVS 可创建高保真且可重现的版本选择流程。
已撤消的版本
如果某些版本应避免使用(例如存在安全漏洞),注册表可以将其声明为 yanked。当选择已撤消的模块版本时,Bazel 会抛出错误。如需修复此错误,请升级到较新的非撤消版本,或使用 --allow_yanked_versions 标志明确允许使用撤消的版本。
兼容性级别
在 Go 中,MVS 关于向后兼容性的假设之所以有效,是因为它将模块的向后不兼容版本视为单独的模块。就 SemVer 而言,这意味着 A 1.x 和 A 2.x 被视为不同的模块,并且可以共存于已解析的依赖关系图中。这之所以能实现,是因为 Go 会将主要版本编码到软件包路径中,因此不会出现任何编译时或链接时冲突。不过,Bazel 无法提供此类保证,因为它遵循的是宽松版本的 SemVer。
因此,Bazel 需要 SemVer 主要版本号的等效项来检测向后不兼容(“破坏性”)的版本。此数字称为兼容性级别,由每个模块版本在其 module() 指令中指定。有了这些信息,如果 Bazel 检测到已解析的依赖项关系图中存在同一模块的不同兼容性级别的版本,便会抛出错误。
最后,增加兼容性级别可能会对用户造成干扰。如需详细了解何时以及如何递增此值,请查看 MODULE.bazel 常见问题解答。
在 MODULE.bazel 文件中指定替换项,以更改 Bazel 模块解析的行为。只有根模块的替换项会生效,如果某个模块用作依赖项,则其替换项会被忽略。
每项替换都针对特定模块名称指定,会影响依赖关系图中的所有版本。虽然只有根模块的替换项会生效,但它们可以用于根模块不直接依赖的传递性依赖项。
单版本替换
single_version_override 有多种用途:
借助 version 属性,您可以将依赖项固定到特定版本,无论依赖项图中请求的是哪个版本的依赖项。
借助 registry 属性,您可以强制此依赖项来自特定注册表,而不是遵循正常的注册表选择流程。
借助 patch* 属性,您可以指定要应用于下载模块的一组补丁。
这些属性都是可选的,可以相互搭配使用。
多版本替换
可以指定 multiple_version_override,以允许同一模块的多个版本在解析的依赖关系图中共存。
您可以为模块指定一个明确的允许版本列表,这些版本必须全部出现在解析前的依赖关系图中 - 必须存在依赖于每个允许版本的某些传递依赖项。解析后,只会保留模块的允许版本,而 Bazel 会将模块的其他版本升级到同一兼容性级别中最近的更高允许版本。如果不存在相同兼容性级别且更高的允许版本,Bazel 会抛出错误。
例如,如果版本 1.1、1.3、1.5、1.7 和 2.0 在解析前的依赖关系图中存在,并且主要版本是兼容性级别,则:
如果多个版本替换项允许 1.3、1.7 和 2.0,则 1.1 会升级到 1.3,1.5 会升级到 1.7,其他版本保持不变。
允许多个版本替换的 1.5 和 2.0 会导致错误,因为 1.7 没有相同兼容性级别的更高版本可供升级。
允许多个版本替换 1.9 和 2.0 会导致错误,因为在解析之前,依赖关系图中不存在 1.9。
此外,用户还可以使用 registry 属性替换注册表,这与单版本替换类似。
非注册表替换项
非注册表替换会从版本解析中完全移除模块。Bazel 不会从注册表中请求这些 MODULE.bazel 文件,而是从代码库本身请求。
Bazel 支持以下非注册表替换项:
archive_override
git_override
local_path_override
请注意,在源归档 MODULE.bazel 中设置版本值在模块被非注册表替换项替换时可能会有缺点。如需详细了解此功能,请参阅MODULE.bazel 常见问题解答。
定义不表示 Bazel 模块的仓库
借助 bazel_dep,您可以定义表示其他 Bazel 模块的代码库。
有时,我们需要定义一个不表示 Bazel 模块的仓库;例如,一个包含要读取为数据的纯 JSON 文件的仓库。
在这种情况下,您可以使用 use_repo_rule 指令通过调用 repo 规则直接定义 repo。此代码库仅对定义它的模块可见。
在底层,这是使用与模块扩展程序相同的机制实现的,可让您更灵活地定义代码库。
代码库名称和严格依赖项
支持模块的仓库的显式名称默认为其模块名称,除非 bazel_dep 指令的 repo_name 属性另有规定。请注意,这意味着模块只能找到其直接依赖项。这有助于防止因传递依赖项发生变化而导致意外中断。
支持模块的代码库的规范名称为 module_name+version(例如 bazel_skylib+1.0.3)或 module_name+(例如 bazel_features+),具体取决于整个依赖关系图中是否存在模块的多个版本(请参阅 multiple_version_override)。请注意,规范名称格式不是您应该依赖的 API,并且随时可能会发生变化。不要对规范名称进行硬编码,而应使用受支持的方式直接从 Bazel 获取该名称:
在 BUILD 和 .bzl 文件中,对从代码库的显示名称(例如,Label.repo_nameLabelLabel("@bazel_skylib").repo_name。
在查找 runfile 时,请使用 $(rlocationpath ...) 或 @bazel_tools//tools/{bash,cpp,java}/runfiles 中的某个 runfile 库,或者对于规则集 rules_foo,使用 @rules_foo//foo/runfiles 中的某个 runfile 库。
从 IDE 或语言服务器等外部工具与 Bazel 互动时,请使用 bazel mod dump_repo_mapping 命令获取给定的一组代码库从表观名称到规范名称的映射。
模块扩展程序还可以将其他代码库引入模块的可见范围。
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-10-01。
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-10-01。"],[],[]]