供应商模式是 Bzlmod 的一项功能,可让您创建外部依赖项的本地副本。这对于离线 build 或您想要控制外部依赖项的来源非常有用。
启用供应商模式
您可以通过指定 --vendor_dir
标志来启用供应商模式。
例如,将其添加到 .bazelrc
文件中:
# Enable vendor mode with vendor directory under <workspace>/vendor_src
common --vendor_dir=vendor_src
供应商目录可以是相对于工作区根目录的相对路径,也可以是绝对路径。
供应特定的外部代码库
您可以将 vendor
命令与 --repo
标志结合使用,以指定要将哪个代码库提供给供应商,它接受规范代码库名称和显式代码库名称。
例如,运行以下命令:
bazel vendor --vendor_dir=vendor_src --repo=@rules_cc
或
bazel vendor --vendor_dir=vendor_src --repo=@@rules_cc+
都会使 rules_cc 在 <workspace root>/vendor_src/rules_cc+
下进行供应商化。
给定目标的供应商外部依赖项
如需为构建给定目标模式所需的所有外部依赖项提供供应商,您可以运行 bazel vendor <target patterns>
。
例如:
bazel vendor --vendor_dir=vendor_src //src/main:hello-world //src/test/...
将使用当前配置供应构建 //src/main:hello-world
目标和 //src/test/...
下的所有目标所需的所有代码库。
在后台,它会执行 bazel build --nobuild
命令来分析目标模式,因此可以将 build 标志应用于此命令并影响结果。
离线构建目标
将外部依赖项作为供应商提供后,您可以通过以下方式离线构建目标:
bazel build --vendor_dir=vendor_src //src/main:hello-world //src/test/...
该 build 应在没有网络访问权限和代码库缓存的干净 build 环境中运行。
因此,您应该能够提交供应商源代码,并在其他机器上离线构建相同的目标。
将所有外部依赖项作为供应商提供
如需将传递外部依赖项图中的所有代码库作为供应商代码库提供,您可以运行以下命令:
bazel vendor --vendor_dir=vendor_src
请注意,将所有依赖项作为供应商提供有一些缺点:
- 提取所有代码库(包括传递引入的代码库)可能需要很长时间。
- 供应商目录可能会变得非常大。
- 如果某些代码库与当前平台或环境不兼容,则可能会提取失败。
因此,请先考虑为特定目标进行供应商开发。
使用 VENDOR.bazel 配置供应商模式
您可以使用位于 vendor 目录下的 VENDOR.bazel 文件来控制如何处理给定代码库。
有两个可用的指令,它们都接受规范代码库名称列表作为参数:
ignore()
:在供应商模式下完全忽略代码库。pin()
:将代码库固定到其当前的供应商来源,就像此代码库具有--override_repository
标志一样。在运行 vendor 命令时,除非取消固定,否则 Bazel 不会更新此代码库的供应商源代码。用户可以手动修改和维护此代码库的供应商源代码。
例如:
ignore("@@rules_cc+")
pin("@@bazel_skylib+")
采用此配置
- 后续的供应商命令将排除这两个代码库。
- Repo
bazel_skylib
将替换为位于 vendor 目录下的源代码。 - 用户可以安全地修改
bazel_skylib
的供应商来源。 - 如需重新分销
bazel_skylib
,用户必须先停用 PIN 声明。
了解供应商模式的运作方式
Bazel 会提取 $(bazel info
output_base)/external
下项目的外部依赖项。将外部依赖项供应商化意味着将相关文件和目录移出到给定的供应商目录,并在后续 build 中使用供应商化的源代码。
要供应商提供的内容包括:
- 代码库目录
- 代码库标记文件
在构建期间,如果第三方标记文件是最新的,或者代码库已固定在 VENDOR.bazel 文件中,则 Bazel 会通过在 $(bazel info output_base)/external
下创建指向该第三方源代码的符号链接来使用该第三方源代码,而不是实际运行代码库规则。否则,系统会输出警告,并且 Bazel 会回退到提取最新版本的代码库。
供应商注册表文件
Bazel 必须执行 Bazel 模块解析,才能提取外部依赖项,这可能需要通过互联网访问注册表文件。为了实现离线 build,Bazel 会将从网络提取的所有注册表文件放置在 <vendor_dir>/_registries
目录下。
供应商符号链接
外部代码库可能包含指向其他文件或目录的符号链接。为确保符号链接正常运行,Bazel 会使用以下策略重写供应商源中的符号链接:
- 创建指向
$(bazel info output_base)/external
的符号链接<vendor_dir>/bazel-external
。它会由每个 Bazel 命令自动刷新。 - 对于供应商源代码,将原来指向
$(bazel info output_base)/external
下的路径的所有符号链接重写为<vendor_dir>/bazel-external
下的相对路径。
例如,如果原始符号链接是
<vendor_dir>/repo_foo+/link => $(bazel info output_base)/external/repo_bar+/file
它将重写为
<vendor_dir>/repo_foo+/link => ../../bazel-external/repo_bar+/file
其中
<vendor_dir>/bazel-external => $(bazel info output_base)/external # This might be new if output base is changed
由于 <vendor_dir>/bazel-external
由 Bazel 自动生成,因此建议将其添加到 .gitignore
或等效位置,以免将其签入。
采用此策略后,即使供应商源代码移至其他位置或 bazel 输出基准发生更改,供应商源代码中的符号链接也应正常运行。