如何在sh_binary目标中正确处理参数并封装供自定义规则调用
实现工具封装的方案
1. 用自定义规则把所有细节藏起来
可以写一个自定义规则,把tool_wrapper的依赖、路径传递这些内部逻辑全封装在规则实现里,让用这个规则的目标只需要简单调用,根本不用关心背后的工具路径或参数。
具体代码示例:
先在my_rules.bzl(或者直接在BUILD文件里)定义规则:
def _my_source_generator_impl(ctx): # 拿到封装好的tool_wrapper可执行文件 tool = ctx.executable.tool_wrapper # 声明要生成的输出文件 output = ctx.actions.declare_file(f"{ctx.attr.name}_generated_src.txt") # 调用工具生成文件,这里不用管内部的$(locations)替换,sh_binary已经处理完了 ctx.actions.run( executable = tool, outputs = [output], arguments = [output.path], # 如果脚本需要输出路径就传这个 ) return DefaultInfo(files = depset([output])) my_source_generator = rule( implementation = _my_source_generator_impl, attrs = { "tool_wrapper": attr.label( executable = True, cfg = "exec", default = Label("//你的tool_wrapper所在路径:tool_wrapper"), # 内部固定这个标签,外部不用管 ), }, )
其他目标用的时候就很简单,完全不用碰外部工具的信息:
my_source_generator( name = "generated_my_src", # 这里啥额外参数都不用加 )
2. 利用sh_binary已有的参数处理逻辑
你已经在sh_binary的args里用$(locations @external//tools:binaries)自动处理路径了,所以自定义规则调用这个sh_binary时,Bazel会自动完成占位符替换,你完全不用在规则里再处理外部工具的路径,相当于把这层细节彻底封装了。
3. 应对工具标签变化的小技巧
如果@external//tools:binaries这个标签以后可能改,可以把它定义成一个常量放在.bzl文件里:
# my_rules.bzl里 EXTERNAL_TOOLS = "@external//tools:binaries"
然后修改sh_binary引用这个常量(要是在.bzl里定义sh_binary的话),或者在BUILD文件里load这个常量来用。以后标签变了只改这一处就行,进一步降低维护成本。
核心注意点
- 自定义规则里的
cfg = "exec"是确保工具在执行配置下构建,适合用来做构建工具。 executable = True告诉Bazel这个标签指向的是可执行文件。- 依赖这个规则的目标完全感知不到
tool_wrapper或者外部二进制文件的存在。
内容的提问来源于stack exchange,提问作者rumbleD5
相关产品推荐
相关产品推荐

