代码库规则

报告问题 查看源代码 每夜版 · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

本页介绍了如何创建代码库规则,并提供了示例以供详细了解。

外部代码库是一种只能在 WORKSPACE 文件中使用的规则,可在 Bazel 的加载阶段启用非封闭操作。每个外部代码库规则都会创建自己的工作区,其中包含自己的 BUILD 文件和制品。它们可用于依赖第三方库(例如 Maven 打包的库),也可用于生成特定于运行 Bazel 的主机的 BUILD 文件。

创建代码库规则

.bzl 文件中,使用 repository_rule 函数创建新的代码库规则,并将其存储在全局变量中。

自定义代码库规则可以像原生代码库规则一样使用。它具有强制性 name 属性,并且其 build 文件中的每个目标都可以称为 @<name>//package:target,其中 <name>name 属性的值。

当您明确构建规则时,或者当规则是 build 的依赖项时,系统会加载该规则。在这种情况下,Bazel 将执行其 implementation 函数。此函数描述了如何创建代码库、其内容和 BUILD 文件。

属性

属性是指规则实参,例如 urlsha256。定义代码库规则时,您必须列出属性及其类型。

local_repository = repository_rule(
    implementation=_impl,
    local=True,
    attrs={"path": attr.string(mandatory=True)})

如需访问属性,请使用 repository_ctx.attr.<attribute_name>

所有 repository_rule 都有隐式定义的属性(就像 build 规则一样)。这两个隐式属性分别是 name(与 build 规则相同)和 repo_mapping。可通过 repository_ctx.name 访问代码库规则的名称。repo_mapping 的含义与原生代码库规则 local_repositorynew_local_repository 的含义相同。

如果属性名称以 _ 开头,则表示该属性是私有的,用户无法设置。

实现函数

每个库规则都需要一个 implementation 函数。它包含规则的实际逻辑,并且严格在加载阶段执行。

该函数只有一个输入参数,即 repository_ctx。该函数会返回 None,表示在给定指定参数的情况下,相应规则是可重现的;或者返回一个字典,其中包含一组参数,这些参数可将相应规则转换为可重现的规则,从而生成相同的代码库。例如,对于跟踪 Git 代码库的规则,这意味着返回特定的提交标识符,而不是最初指定的浮动分支。

输入参数 repository_ctx 可用于访问属性值和非密封函数(查找二进制文件、执行二进制文件、在代码库中创建文件或从互联网下载文件)。如需了解更多背景信息,请参阅该库。示例:

def _impl(repository_ctx):
  repository_ctx.symlink(repository_ctx.attr.path, "")

local_repository = repository_rule(
    implementation=_impl,
    ...)

实现函数何时执行?

如果代码库声明为 local,则依赖关系图中的依赖项(包括 WORKSPACE 文件本身)发生更改时,将导致执行实现函数。

如果实现函数请求的依赖项缺失,则可以重新启动该函数。在依赖项得到解决后,将重新执行实现函数的开头部分。为避免不必要的重启(这会很耗费资源,因为可能需要重复进行网络访问),系统会预提取标签实参,前提是所有标签实参都可以解析为现有文件。请注意,从仅在函数执行期间构建的字符串或标签解析路径仍可能会导致重新启动。

最后,对于非 local 代码库,只有以下依赖项的更改可能会导致重新启动:

  • 定义代码库规则所需的 .bzl 文件。
  • WORKSPACE 文件中声明代码库规则。
  • 使用 repository_rule 函数的 environ 属性声明的任何环境变量的值。可以使用 --action_env 标志从命令行强制执行这些环境变量的值(但此标志会使 build 的所有操作失效)。
  • 标签使用和引用的任何文件的内容(例如 //mypkg:label.txt 而不是 mypkg/label.txt)。

强制重新提取外部代码库

有时,外部代码库可能会过时,即使其定义或依赖项没有任何变化也是如此。例如,提取来源的代码库可能会跟踪第三方代码库的特定分支,并且该分支上提供了新的提交。在这种情况下,您可以调用 bazel sync,让 Bazel 无条件重新提取所有外部代码库。

此外,有些规则会检查本地机器,如果本地机器升级,这些规则可能会过时。在此处,您可以要求 Bazel 仅重新提取 repository_rule 定义设置了 configure 属性的外部代码库,使用 bazel sync --configure

示例

  • C++ 自动配置的工具链:它使用代码库规则,通过查找本地 C++ 编译器、环境和 C++ 编译器支持的标志,自动为 Bazel 创建 C++ 配置文件。

  • Go 代码库使用多个 repository_rule 来定义使用 Go 规则所需的依赖项列表。

  • rules_jvm_external 默认情况下会创建一个名为 @maven 的外部代码库,该代码库会为传递依赖项树中的每个 Maven 制品生成 build 目标。