如何在 Bazel 中动态生成 Rule 的 deps(基于插件目录结构)

1次阅读

如何在 Bazel 中动态生成 Rule 的 deps(基于插件目录结构)

本文介绍如何利用 subpackages() 函数(推荐来自 bazel_skylib 的版本)自动发现并引用多个子包中的目标,避免在根 build 文件中硬编码依赖路径,实现可扩展、可维护的插件式依赖管理。

本文介绍如何利用 subpackages() 函数(推荐来自 bazel_skylib 的版本)自动发现并引用多个子包中的目标,避免在根 build 文件中硬编码依赖路径,实现可扩展、可维护的插件式依赖管理。

在构建大型、模块化 Python 项目(如插件系统)时,手动维护 deps 列表极易出错且难以扩展。例如,当新增 plugin3/ 目录后,必须同步修改根 BUILD 文件——这违背了 Bazel “声明即配置” 和“可复现构建”的设计哲学。

Bazel 原生 glob() 仅匹配文件路径,无法解析 target;而 native.subpackages()(已废弃)或更优的 bazel_skylib 提供的 subpackages 才是解决动态 target 发现的正确工具。

✅ 推荐方案:使用 bazel_skylib 的 subpackages

首先,在工作区根目录的 WORKSPACE 或 MODULE.bazel 中引入 bazel_skylib(Bazel ≥ 6.0 推荐用 MODULE):

# MODULE.bazel bazel_dep(name = "bazel_skylib", version = "1.5.0")

然后,在 //plugins_folder/BUILD 中定义各插件的 py_library,并导出统一别名(如 all):

# plugins_folder/plugin1/BUILD py_library(     name = "code1-0",     srcs = ["code1-0.py"], )  py_library(     name = "code1-1",     srcs = ["code1-1.py"], )  # 导出聚合目标(关键!) py_library(     name = "all",     srcs = [],     deps = [":code1-0", ":code1-1"], )

同理为 plugin2/ 编写 BUILD,确保每个插件子目录均提供 :all 目标。

最后,在根 //plugins_folder/BUILD 中动态聚合所有插件依赖:

# plugins_folder/BUILD load("@bazel_skylib//lib:subpackages.bzl", "subpackages")  py_library(     name = "code0",     srcs = ["code0.py"],     deps = [         "//plugins_folder/%s:all" % pkg         for pkg in subpackages(include = ["plugin*"])     ], )

? subpackages(include = [“plugin*”]) 返回形如 [“plugin1”, “plugin2”] 的字符串列表,不包含前导 /,也不含 //plugins_folder/ 前缀——因此拼接时需显式补全完整包路径。

? 验证与调试

运行以下命令确认依赖图是否符合预期:

bazel query 'deps(//plugins_folder:code0)' --notool_deps --noimplicit_deps

输出应包含 //plugins_folder/plugin1:all、//plugins_folder/plugin2:all 及其内部 targets(如 :code1-0, :code2-0 等)。

⚠️ 注意事项

  • 每个插件子目录 必须存在 BUILD 文件,且其中需明确定义 :all(或其他约定名称)目标;
  • subpackages() 在加载阶段执行,不支持条件逻辑或 runtime 计算,但足以满足静态目录结构发现;
  • 若需更细粒度控制(如排除测试插件),可用 exclude = [“plugin_test”] 参数;
  • 不要混用原生 native.subpackages()(自 Bazel 6.0 起标记为 deprecated)与 bazel_skylib 版本。

通过该模式,新增插件只需创建目录 + BUILD 文件,无需触碰根构建配置,真正实现“零配置扩展”,大幅提升工程可维护性与协作效率。

text=ZqhQzanResources