Bazel 支持外部依赖项,使用的源文件(文本和二进制文件) 例如,它们可以是 托管在 GitHub 代码库、Maven 工件或本地目录中的某个规则集 当前工作区外的任何机器
从 Bazel 6.0 开始,您可以通过以下两种方式使用 Bazel 管理外部依赖项:
以仓库为中心的传统 WORKSPACE
系统,以及
以模块为中心的较新 MODULE.bazel
系统(代号为 Bzlmod),
并通过 --enable_bzlmod
标记启用)。这两个系统可以
但 Bzlmod 将在未来的 Bazel 中取代 WORKSPACE
系统
请参阅 Bzlmod 迁移指南,了解如何
迁移。
本文档介绍了与外部依赖项管理相关的概念 ,然后再按顺序详细了解这两个系统。
概念
代码库
一个目录树,其根目录下有一个边界标记文件,该文件包含源代码 支持在 Bazel 构建中使用的各种文件通常缩写为“repo”。
代码库边界标记文件可以是 MODULE.bazel
(表示此代码库
表示 Bazel 模块)、REPO.bazel
(请参阅下文)或
WORKSPACE
或 WORKSPACE.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 构建的依赖关系图 模块。
Bzlmod 上的外部链接
- bazelbuild/examples 中的 bzlmod 用法示例
- Bazel 外部依赖项检查 (原始 Bzlmod 设计文档)
- Bzlmod 2021 年 BazelCon 讲座
- 有关 Bzlmod 的 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
依赖于B
和C
;B
和C
均依赖于不同版本的D
)。
- 这也有自己的问题:宏无法
由于 WORKSPACE 的缺点,Bzlmod 将取代旧版 WORKSPACE 系统。请阅读 Bzlmod 迁移 有关如何迁移到 Bzlmod 的指南。