外部依赖项概览

<ph type="x-smartling-placeholder"></ph> 报告问题 <ph type="x-smartling-placeholder"></ph> 查看来源 每晚 · 7.2 条 · 7.1敬上 · 7.0 · 6.5 · 6.4

Bazel 支持外部依赖项,使用的源文件(文本和二进制文件) 例如,它们可以是 托管在 GitHub 代码库、Maven 工件或本地目录中的某个规则集 当前工作区外的任何机器

从 Bazel 6.0 开始,您可以通过以下两种方式使用 Bazel 管理外部依赖项: 以仓库为中心的传统 WORKSPACE 系统,以及 以模块为中心的较新 MODULE.bazel 系统(代号为 Bzlmod), 并通过 --enable_bzlmod 标记启用)。这两个系统可以 但 Bzlmod 将在未来的 Bazel 中取代 WORKSPACE 系统 请参阅 Bzlmod 迁移指南,了解如何 迁移。

本文档介绍了与外部依赖项管理相关的概念 ,然后再按顺序详细了解这两个系统。

概念

代码库

一个目录树,其根目录下有一个边界标记文件,该文件包含源代码 支持在 Bazel 构建中使用的各种文件通常缩写为“repo”

代码库边界标记文件可以是 MODULE.bazel(表示此代码库 表示 Bazel 模块)、REPO.bazel(请参阅下文)或 WORKSPACEWORKSPACE.bazel。任何 Repo 边界标记文件 表示代码库的边界;多个此类文件可以共存 目录。

主代码库

运行当前 Bazel 命令的代码库。

主代码库的根目录也称为 工作区根目录

工作区

所有 Bazel 命令共享的环境在同一主代码库中运行。它 包含主代码库以及所有已定义的外部代码库的集合。

请注意,过去“仓库”的概念和“workspace”曾经 混淆;术语“工作区”通常用于指代 有时甚至被用作“仓库”的同义词。

规范代码库名称

可供代码库寻址的规范名称。在 工作区,每个代码库都有一个规范名称。代码库中的目标 规范名称为 canonical_name 时,可以使用 @@canonical_name//package:target(请注意双 @)。

主代码库始终使用空字符串作为规范名称。

显而易见的代码库名称

代码库可在其他某个代码库的上下文中寻址的名称。 可以将其视为代码库的“昵称”:具有规范名称的代码库 michael 在代码库上下文中可能具有表观名称 mike alice,但在代码库上下文中可能具有表观名称 mickey bob。在这种情况下,michael 内的目标可以通过标签 alice 上下文中的 @mike//package:target(请注意单个 @)。

反过来,这也可以理解为代码库映射:每个代码库 维护从“apparent repo name”的映射“规范代码库名称”

仓库规则

代码库定义的架构,用于告知 Bazel 如何具体化 存储库例如,可能是“从特定网址下载 zip 归档文件 或“提取某个 Maven 工件,并将其作为 java_import 目标”,或只是“为本地目录添加符号链接”。每个代码库 定义:调用具有适当数量参数的 Repo 规则。

如需详细了解如何写入,请参阅代码库规则 自己的代码库规则

到目前为止,最常见的代码库规则是 http_archive:用于下载归档文件 并将其提取,然后 local_repository,用于以符号链接 已经是 Bazel 代码库的本地目录。

提取代码库

通过运行与代码库的关联 repo 规则。工作区中定义的代码库不适用于本地磁盘 然后再被提取

通常,Bazel 仅在需要代码库的内容时才获取代码库, 并且尚未提取该代码库。如果已提取代码库 那么 Bazel 只有在定义更改的情况下才会重新获取。

fetch 命令可用于启动代码库的预提取操作, 目标或所有必要的代码库。此功能 使用 --nofetch 选项启用离线构建。

--fetch 选项用于管理网络访问权限。其默认值为 true。 不过,如果设置为 false (--nofetch),该命令将使用所有已缓存的 如果不存在,则该命令会导致 失败。

如需了解详情,请参阅提取选项 与控制抓取相关的信息。

目录布局

提取后,代码库可在以下位置的子目录 external 中找到: 输出基准

您可以运行以下命令来查看使用 规范名称 canonical_name

ls $(bazel info output_base)/external/ canonical_name 

REPO.bazel 文件

REPO.bazel 文件用于标记目录树的最顶层边界 后者构成了代码库它无需包含任何内容即可用作代码库 边界文件;不过,它也可以用来指定 代码库内的所有构建目标

REPO.bazel 文件的语法与 BUILD 文件的语法类似,只不过前者没有 支持 load 语句,且只有一个函数 repo() 可用。repo() 采用的参数与 package() 相同 function(位于BUILD文件中);而 package() 为软件包内的所有构建目标指定通用属性,repo() 以类似方式对代码库中的所有构建目标执行此操作。

例如,您可以通过以下命令为代码库中的所有目标指定一个通用许可: 拥有以下 REPO.bazel 文件:

repo(
    default_package_metadata = ["//:my_license"],
)

使用 Bzlmod 管理外部依赖项

新的外部依赖项子系统 Bzlmod 不直接使用 Repo 定义。而是从模块构建依赖关系图,运行 扩展,并相应地定义代码库。

Bazel 模块是指可以有多个 每个版本都会发布所依赖的其他模块的相关元数据 。模块的 Repo 根目录下必须有一个 MODULE.bazel 文件, WORKSPACE 文件。这个文件是模块的清单,声明了其名称 版本、依赖项列表等信息。以下是 示例:

module(name = "my-module", version = "1.0")

bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")

模块只能列出其直接依赖项,Bzlmod 会在 Bazel 注册表 - 默认情况下,Bazel 中心 注册表。域名注册管理机构提供 依赖项MODULE.bazel 文件,借助它,Bazel 能够发现整个 传递依赖关系图。

在版本解决方案(为每个模块选择一个版本)之后, Bazel 再次查询注册表,以了解如何为每个模块定义代码库 (在大多数情况下,使用 http_archive)。

模块还可以指定称为“标记”的自定义数据, 在模块解析后模块扩展所消耗的时间 定义其他代码库这些扩展程序的功能类似于 repo 规则,使它们能够执行文件 I/O 和发送网络等操作 请求。除此之外,它们还允许 Bazel 与其他软件包进行交互 管理系统,同时遵循由 Bazel 构建的依赖关系图 模块。

使用 WORKSPACE 定义代码库

过去,您可以通过在 WORKSPACE(或 WORKSPACE.bazel)文件。此文件的语法与 BUILD 文件,采用代码库规则而不是构建规则。

以下代码段举例说明了如何在http_archive WORKSPACE 文件:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "foo",
    urls = ["https://example.com/foo.zip"],
    sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96",
)

该代码段定义了一个规范名称为 foo 的代码库。在WORKSPACE中 默认情况下,代码库的规范名称也是 所有其他代码库

如需查看可用函数的完整列表,请参阅 WORKSPACE 个文件。

WORKSPACE 系统的缺点

自推出 WORKSPACE 系统以来的几年里,有用户报告 许多痛点,包括:

  • Bazel 不会评估任何依赖项的 WORKSPACE 文件,因此 传递依赖项必须在主方法的 WORKSPACE 文件中定义 以及直接依赖项
  • 为解决此问题,项目采用“deps.bzl”模式,其中 他们定义了一个宏,而该宏又定义了多个代码库,并要求用户 在其 WORKSPACE 文件中调用此宏。
    • 这也有自己的问题:宏无法 load 其他 .bzl 文件,因此 这些项目必须在此配置文件中定义其传递依赖项 “deps”宏,也可通过让用户多次调用 分层“依赖项”宏。
    • Bazel 依序评估 WORKSPACE 文件。此外, 依赖项使用 http_archive 和网址指定,其中不包含任何 版本信息。这意味着没有可靠的方法 对于 Diamond 依赖项(A 依赖于 BCBC 均依赖于不同版本的 D)。

由于 WORKSPACE 的缺点,Bzlmod 将取代旧版 WORKSPACE 系统。请阅读 Bzlmod 迁移 有关如何迁移到 Bzlmod 的指南