本页面介绍了如何定义代码库规则,并提供了示例以了解更多 详情。
外部代码库是一个目录树,
其中包含可在 Bazel 构建中使用的源文件,这些文件通过
运行其对应的 代码库规则 按需生成。代码库可以通过多种方式定义,但最终,每个代码库都是通过调用代码库规则来定义的,就像构建目标是通过调用构建规则来定义的一样。它们可用于依赖
第三方库(例如 Maven 打包的库),也可用于生成
BUILD文件特定于 Bazel 运行所在主机的。
代码库规则定义
在 .bzl 文件中,使用
repository_rule 函数定义
新的代码库规则并将其存储在全局变量中。定义代码库规则后,
可以将其作为函数调用以定义代码库。此调用通常
在 模块扩展实现
函数内执行。
代码库规则定义的两个主要组成部分是其属性架构和 实现函数。属性架构决定了传递给代码库规则调用的 属性的名称和类型,而实现函数会在需要提取代码库时 运行。
属性
属性是传递给代码库规则调用的实参。代码库规则接受的
属性的架构在使用 repository_rule 调用定义代码库规则时使用 attrs 实参指定。以下示例将
url 和 sha256 属性定义为字符串:
http_archive = repository_rule(
implementation=_impl,
attrs={
"url": attr.string(mandatory=True),
"sha256": attr.string(mandatory=True),
}
)
如需在实现函数中访问属性,请使用
repository_ctx.attr.<attribute_name>:
def _impl(repository_ctx):
url = repository_ctx.attr.url
checksum = repository_ctx.attr.sha256
所有 repository_rule 都有隐式定义的属性 name。这是一个
字符串属性,其行为有些神奇:当指定为
代码库规则调用的输入时,它会采用明显的代码库名称;但当使用 repository_ctx.attr.name 从
代码库规则的实现函数中读取时,它会返回
规范的代码库名称。
实现函数
每个代码库规则都需要一个 implementation 函数。它包含规则的实际
逻辑,并且严格在加载阶段执行。
该函数正好有一个输入形参 repository_ctx。该函数
会返回 None,表示给定
指定形参时规则是可重现的;或者返回一个字典,其中包含一组用于该规则的形参,这些形参会
将该规则转换为可重现的规则,从而生成相同的代码库。例如,对于跟踪 Git 代码库的规则,这意味着返回特定的提交标识符,而不是最初指定的可变分支。
输入形参 repository_ctx 可用于访问属性值和
非 hermetic 函数(查找二进制文件、执行二进制文件、在
代码库中创建文件或从互联网下载文件)。如需了解更多背景信息,请参阅 API
文档。示例:
def _impl(repository_ctx):
repository_ctx.symlink(repository_ctx.attr.path, "")
local_repository = repository_rule(
implementation=_impl,
...)
实现函数何时执行?
当 Bazel 需要该代码库中的目标时,例如当另一个目标(在另一个代码库中)依赖于该目标时,或者当该目标在命令行中被提及时,系统会执行代码库规则的实现函数。然后,实现函数应在文件系统中创建代码库。这称为“提取” 代码库。
与常规目标不同,当 某些更改会导致代码库发生变化时,系统不一定会重新提取代码库。这是因为 Bazel 无法检测到某些更改,或者在每次构建时检测这些更改会导致 开销过大(例如,从 网络提取的内容)。因此,只有在以下某项发生变化时,系统才会重新提取代码库:
- 传递给代码库规则调用的属性。
- 构成代码库规则实现的 Starlark 代码。
- 传递给
repository_ctx'sgetenv()方法或使用environ属性声明的任何环境变量的值repository_rule。这些环境变量的值可以使用--repo_env标志在命令行中硬编码。 - 代码库规则的实现函数中被
watched的任何路径的存在、内容和类型。- 某些其他具有
watch形参的repository_ctx方法(例如read()、execute()和extract())也可能会导致路径被监视。 - 同样,
repository_ctx.watch_tree和path.readdir可能会以其他方式导致路径 被监视。
- 某些其他具有
- 执行
bazel fetch --force时。
repository_rule 有两个形参用于控制何时重新提取代码库
:
- 如果设置了
configure标志,则系统会在bazel fetch --force --configure上重新提取代码库(不会重新提取非configure代码库)。 - 如果设置了
local标志,除了上述情况外,当 Bazel 服务器重启时,系统也会 重新提取代码库。
强制重新提取外部代码库
有时,外部代码库可能会过时,而其
定义或依赖项没有任何变化。例如,提取来源的代码库可能会遵循第三方代码库的
特定分支,并且该分支上有新的提交。在这种情况下,您可以要求 Bazel 无条件地重新提取所有外部代码库
,方法是调用 bazel fetch --force --all。
此外,某些代码库规则会检查本地机器,如果
本地机器已升级,则可能会过时。在这里,您可以要求 Bazel 仅重新提取那些
外部代码库,其中 repository_rule
定义设置了 configure 属性,使用 bazel fetch --force
--configure。
示例
C++ 自动配置的 工具链: 它使用代码库规则通过查找本地 C++ 编译器、环境和 C++ 编译器支持的标志,自动为 Bazel 创建 C++ 配置文件。
Go 代码库 使用多个
repository_rule来定义使用 Go 规则所需的依赖项列表。rules_jvm_external 默认创建一个名为
@maven的外部代码库,该代码库会为传递依赖项树中的每个 Maven 工件生成 构建目标。