如何用Bazel genrule为每个include文件添加对应命令行选项
为Bazel Genrule中的每个Include文件自动添加--include选项
我有一款命令行工具,支持通过重复的--include选项传入多个文件,使用示例如下:
mytool --include=some_include1 --include=some_include2 --include=... source1 source2 ...
我编写了如下Bazel规则:
filegroup( name = "include_group", srcs = ["some_include1", "some_include2"], ) filegroup( name = "source_group", srcs = ["source1", "source2"], ) genrule( name = "myrule", srcs = [":include_group"] + [":source_group"], outs = ["out.cpp"], tools = ["mytool"], cmd = "$(location :mytool) --include=$(locations :include_group) $(locations :source_group)" )
但生成的实际命令行结果不符合预期:
mytool --include=some_include1 some_include2 source1 source2
可以看到第二个include文件some_include2缺失了--include前缀,需要为include_group中的每个文件都自动添加对应的--include选项。
解决方法
方法1:使用Bazel内置的$(foreach)函数
直接修改genrule的cmd字段,利用foreach遍历每个include文件并拼接前缀:
genrule( name = "myrule", srcs = [":include_group", ":source_group"], outs = ["out.cpp"], tools = ["mytool"], cmd = "$(location :mytool) $(foreach include,$(locations :include_group),--include=$(include)) $(locations :source_group)" )
$(foreach var, list, expr)会遍历list中的每个元素,将var替换为当前元素后展开expr。这里会为每个include文件生成--include=文件路径的字符串,最终所有字符串以空格分隔,完全符合工具的参数要求。
方法2:自定义Starlark规则(适用于复杂场景)
如果需要更灵活的参数处理或复用逻辑,可以编写自定义Starlark规则。创建mytool_rule.bzl文件:
def _mytool_rule_impl(ctx): tool = ctx.executable.tool includes = ctx.files.includes sources = ctx.files.sources output = ctx.outputs.out args = ctx.actions.args() # 为每个include添加--include前缀 for include in includes: args.add("--include", include.path) # 添加所有源文件 args.add_all(sources) ctx.actions.run( inputs = includes + sources, outputs = [output], executable = tool, arguments = [args], ) mytool_rule = rule( implementation = _mytool_rule_impl, attrs = { "tool": attr.label(executable = True, cfg = "exec", mandatory = True), "includes": attr.label_list(allow_files = True, mandatory = True), "sources": attr.label_list(allow_files = True, mandatory = True), "out": attr.output(mandatory = True), }, )
在BUILD文件中加载并使用该规则:
load("//path/to:mytool_rule.bzl", "mytool_rule") mytool_rule( name = "myrule", tool = ":mytool", includes = [":include_group"], sources = [":source_group"], out = "out.cpp", )
这种方式可读性和可维护性更强,适合后续扩展复杂的参数逻辑。
内容的提问来源于stack exchange,提问作者Alexander Chen
相关产品推荐
相关产品推荐

