如何通过命令行参数实现Bazel规则生成filegroup并依赖动态目标
Bazel动态创建依赖命令行指定路径的filegroup
我需要实现:执行Bazel构建命令时传入一个路径(或目录名),将该路径下所有文件纳入一个filegroup,作为其他目标的依赖。指定目录下已存在BUILD.bazel文件,但折腾一整天仍未解决。
我尝试的代码如下:
def _impl(ctx): my_setting_value = ctx.build_setting_value all_files = native.glob(["<path to>/" + my_setting_value + "/**"]) ctx.actions.declare_file_group( name = ctx.label.name + "_group", srcs = all_files, ) custom_filegroup = rule( implementation = _impl, build_setting = config.string(flag = True), outputs = { "my_custom_filegroup": "%{name}_group", }, )
随后在BUILD文件中定义目标:
custom_filegroup(name = "my_files", build_setting_default="")
并将":my_files.my_custom_filegroup"作为依赖添加到另一目标。执行bazel build //<path to>:my_files时,持续收到错误:
"glob错误:'native.glob'只能在加载阶段调用"
问题根源
native.glob是Bazel加载阶段的API,仅能在BUILD文件、宏或扩展的加载阶段调用,不能用于规则的实现函数(属于分析/执行阶段)。规则实现阶段必须使用Bazel提供的阶段安全API来获取文件。
正确实现方案
1. 定义自定义规则与构建设置
在.bzl扩展文件或BUILD文件中编写:
load("@bazel_skylib//lib:paths.bzl", "paths") def _custom_filegroup_impl(ctx): target_path = ctx.build_setting_value if not target_path: fail("必须通过命令行传入路径,示例:--//<path to>:my_files=<目标路径>") # 基于当前包目录拼接完整路径 full_path = paths.join(ctx.label.package, target_path) # 使用ctx.glob获取文件(执行阶段安全API) all_files = ctx.glob([full_path + "/**"]) # 声明文件组并通过提供者暴露 file_group = ctx.actions.declare_file_group( name = ctx.label.name + "_files", srcs = all_files, ) return [ DefaultInfo(files = depset(all_files)), OutputGroupInfo(my_custom_filegroup = file_group), ] custom_filegroup = rule( implementation = _custom_filegroup_impl, build_setting = config.string(flag = True), provides = [OutputGroupInfo], )
2. 在BUILD文件中定义目标与依赖
custom_filegroup(name = "my_files", build_setting_default="") # 示例依赖目标(以cc_binary为例) cc_binary( name = "my_binary", srcs = ["main.cc"], # 方式1:直接依赖规则,通过DefaultInfo获取所有文件 data = [":my_files"], # 方式2:依赖指定输出组 # data = [":my_files.my_custom_filegroup"], )
3. 执行构建命令
bazel build //<path to>:my_binary --//<path to>:my_files=relative/path/to/dir
其中relative/path/to/dir是相对于当前包目录的路径,也可以使用以工作区根目录为基准的绝对路径。
额外说明
- 若未引入
@bazel_skylib,需在WORKSPACE文件中添加:load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "bazel_skylib", sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d", urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz"], )
内容的提问来源于stack exchange,提问作者Amir
相关产品推荐
相关产品推荐

