如何用 Bazel vendor 模式获取外部依赖本地副本并离线构建?
2026/9/14 20:24:47 网站建设 项目流程

如何用 Bazel vendor 模式获取外部依赖本地副本并离线构建?

【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel

Bazel 项目默认从网络拉取外部依赖,构建机一旦断网或需要控制依赖来源,构建就会失败。Bazel 的 vendor 模式可以把外部依赖抓取到工作区内的一个目录,形成可入库的本地副本,之后构建直接使用这份副本,实现离线构建。本文基于 Bazel vendor 模式文档 说明完整的操作路径:开启 vendor 模式、把依赖 vendor 到本地、离线构建,以及如何用VENDOR.bazel管理已 vendor 的仓库。

开启 vendor 模式

vendor 模式通过--vendor_dir标志启用,该参数指定存放外部依赖本地副本的目录。路径可以是相对于工作区根目录的相对路径,也可以是绝对路径。

最方便的做法是把它写进.bazelrc,让所有命令默认生效:

# Enable vendor mode with vendor directory under <workspace>/vendor_src common --vendor_dir=vendor_src

这样 vendor 目录位于<workspace>/vendor_src。也可以不在.bazelrc中配置,而是在每条命令后手动追加--vendor_dir=vendor_src

将目标依赖 vendor 到本地副本

文档推荐的做法是先只 vendor 构建特定目标所需的依赖,而不是把全部依赖都拉下来。

只 vendor 构建目标所需的依赖

bazel vendor --vendor_dir=vendor_src //src/main:hello-world //src/test/...

该命令会 vendor 出构建//src/main:hello-world以及//src/test/...下所有目标在当前配置下所需的全部仓库。底层实际上是执行一次bazel build --nobuild来分析这些 target pattern,因此附加在命令上的构建类标志会影响分析结果,进而影响最终 vendor 了哪些仓库。

只 vendor 指定仓库

如果只想把某一个外部仓库 vendor 下来,用--repo标志指定仓库名,它同时接受 canonical repo name 和 apparent repo name 两种写法:

bazel vendor --vendor_dir=vendor_src --repo=@rules_cc

bazel vendor --vendor_dir=vendor_src --repo=@@rules_cc+

两种写法都会把rules_ccvendor 到<workspace root>/vendor_src/rules_cc+下。

可选分支:vendor 全部依赖

bazel vendor --vendor_dir=vendor_src

这条命令会 vendor 传递依赖图中的所有仓库,文档明确列出它的几个缺点:

  • 拉取所有仓库(包括传递引入的)可能很耗时;
  • vendor 目录会变得非常大;
  • 某些与当前平台或环境不兼容的仓库可能拉取失败。

因此文档建议优先按目标 vendor,而不是全量 vendor。

离线构建并验证结果

依赖 vendor 完成后,用同样的--vendor_dir构建即可:

bazel build --vendor_dir=vendor_src //src/main:hello-world //src/test/...

验证标准来自文档的两条说明:

  1. 构建应在没有网络访问、也没有 repository cache的干净构建环境中正常工作;
  2. 由于 vendor 出的源码可以 check in 到代码仓库,你可以在另一台机器上拉取代码后离线构建同样的目标。

换句话说,判断 vendor 是否覆盖完整的方式就是:在无网络、无缓存的环境下执行上面的构建命令,若能成功即说明当前目标所需的依赖都已 vendor 到位。

文档还给出一个需要重新 vendor 的边界条件:如果你修改了待构建的目标、外部依赖、构建配置,或者更换了 Bazel 版本,需要重新执行 vendor 命令,否则离线构建可能失败。

用 VENDOR.bazel 管理已 vendor 的仓库

vendor 目录下的VENDOR.bazel文件控制各个仓库在 vendor 模式下的处理方式。文件中有两个指令,参数都是 canonical repo name 列表:

  • ignore():让 vendor 模式完全忽略某个仓库;
  • pin():把仓库固定为其当前已 vendor 的源码,效果相当于对该仓库加了一个--override_repository标志。运行 vendor 命令时 Bazel 不会更新被 pin 仓库的源码(除非取消 pin),你可以手工修改并维护这份已 vendor 的源码。

示例配置:

ignore("@@rules_cc+") pin("@@bazel_skylib+")

配置后的行为:

  • 两个仓库都会从后续的 vendor 命令中排除;
  • bazel_skylib会被 override 为 vendor 目录下的源码,可以安全地手工修改;
  • 如果要重新 vendorbazel_skylib,必须先移除这条 pin 语句。

另外,设置了localconfigure为 true 的 repository rule 始终会被排除在 vendor 之外,无法通过 vendor 模式接管。

理解 vendor 模式的内部机制(影响排障)

vendor 的本质是:Bazel 平时把外部依赖放在$(bazel info output_base)/external下,vendor 模式把相关文件和目录移动到 vendor 目录,后续构建直接使用这份副本。被 vendor 的内容包括仓库目录本身和仓库的 marker 文件。

构建时的选择逻辑:如果 vendored marker 文件是最新的,或者仓库在VENDOR.bazel中被 pin,Bazel 会在$(bazel info output_base)/external下创建指向 vendor 源码的符号链接来使用它,而不是重新执行 repository rule;否则 Bazel 打印一条 warning 并回退到抓取该仓库的最新版本。如果你在没有 pin 的情况下手工修改了 vendor 源码,修改会被使用,但一旦 marker 过期并再次 vendor,这份源码会被覆盖。

两个与离线构建直接相关的细节:

  • Registry 文件:Bazel 模块解析可能需要访问 registry 文件,vendor 时会把从网络拉取的 registry 文件一并 vendor 到<vendor_dir>/_registries目录,这是离线构建能走通模块解析的前提。
  • 符号链接:Bazel 会自动创建<vendor_dir>/bazel-external指向$(bazel info output_base)/external,并把 vendor 源码中原先指向 output base 下 external 目录的符号链接改写为<vendor_dir>/bazel-external下的相对路径,因此 vendor 源码移动到别处或 output base 变化后符号链接仍可用。bazel-external由 Bazel 自动生成,文档建议把它加入.gitignore,避免 check in。注意两类边界:指向$(bazel info output_base)/external之外的绝对路径符号链接不会被改写,仍可能破坏跨机器兼容性;Windows 上 vendor 符号链接需要启用--windows_enable_symlinks标志才有效。

离线环境下使用 bazel 子命令的补充项

一些 Bazel 子命令(如bazel mod tidy)有隐式的工具依赖,这些工具无法从用户构建目标到达,因此bazel vendor //...默认不会包含它们。如果计划离线或 hermetic 环境(例如配合--vendor_dir--nofetch)中运行bazel mod tidy这类命令,需要把@bazel_tools//tools:tools_for_bazel_subcommands这个 filegroup 加入 vendor 调用:

bazel vendor //... @bazel_tools//tools:tools_for_bazel_subcommands

小结

一条最短可行路径是:在.bazelrc中加common --vendor_dir=vendor_src,执行bazel vendor --vendor_dir=vendor_src <目标 pattern>,然后用bazel build --vendor_dir=vendor_src <同样的目标>在无网络、无 repository cache 的环境中验证构建通过。需要固定或排除某些仓库时用 vendor 目录下的VENDOR.bazel配置pin()/ignore();目标、依赖、构建配置或 Bazel 版本变化后要重新 vendor。更多背景可参考 外部依赖总览 和 vendor 模式文档。

【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询