供应商模式

报告问题 查看来源 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

借助供应商模式,您可以创建外部依赖项的本地副本。这对于离线 build 或您想要控制外部依赖项的来源时非常有用。

启用供应商模式

您可以通过指定 --vendor_dir 标志来启用供应商模式。

例如,通过将其添加到 .bazelrc 文件中:

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

供应商目录可以是相对于工作区根目录的相对路径,也可以是绝对路径。

提供特定外部代码库

您可以将 vendor 命令与 --repo 标志结合使用,以指定要纳入供应商的 repo,该标志接受规范 repo 名称表观 repo 名称

例如,运行:

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

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

都将获取在 <workspace root>/vendor_src/rules_cc+ 下进行供应商化的 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 命令来分析目标模式,因此构建标志可以应用于此命令并影响结果。

离线构建目标

在外部依赖项已纳入 vendor 目录的情况下,您可以通过以下方式离线构建目标

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

该 build 应能在没有网络访问权限和代码库缓存的干净 build 环境中正常运行。

因此,您应该能够签入供应商提供的源代码,并在另一台机器上离线构建相同的目标。

将所有外部依赖项纳入 vendor

如需将传递性外部依赖项图中的所有代码库都纳入供应商目录,您可以运行以下命令:

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 中使用供应商化来源。

供应商提供的内容包括:

  • 代码库目录
  • 代码库标记文件

在 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 输出库发生更改后,供应商提供的源代码中的符号链接也能正常工作。