Bazel自定义run_shell规则如何配置data依赖使其进入执行沙箱
Bazel自定义规则data依赖不生效解决方案
问题描述
查看Bazel shell_command规则示例时,尝试给自定义规则添加data依赖。按照官方文档配置label_list类型的data属性后,data依赖不会被自动拷贝到沙箱中。
当前规则实现代码:
# This example copied from docs def _emit_size_impl(ctx): in_file = ctx.file.file out_file = ctx.actions.declare_file("%s.pylint" % ctx.attr.name) ctx.actions.run_shell( inputs = [in_file], outputs = [out_file], command = "wc -c '%s' > '%s'" % (in_file.path, out_file.path), ) return [DefaultInfo(files = depset([out_file]),)] emit_size = rule( implementation = _emit_size_impl, attrs = { "file": attr.label(mandatory = True,allow_single_file = True,), "data": attr.label_list(allow_files = True), # ^^^^^^^ 仅声明该属性不足以将data依赖拷贝到沙箱 }, )
规则调用方式:
emit_size(name = "my_name", file = "my_file", data = ["my_data"])
预期效果:命令执行前my_data会被拷贝到bazel-out对应的沙箱目录中。
根因
仅在attrs中声明data属性不会自动将对应文件加入action的输入列表。Bazel不会隐式推断action需要的依赖文件,所有沙箱中需要访问的文件必须显式传入action的inputs参数,否则不会被提前准备到沙箱环境,这是Bazel保证增量构建正确性的核心设计。
修复方案
- 通过
ctx.files.data获取data属性关联的所有文件列表 - 将data文件和原有的输入文件合并,传入
run_shell的inputs参数 - (可选)如果需要让依赖当前规则的上层目标也能拿到这些data依赖,将data文件加入DefaultInfo的runfiles中传递
修改后的完整实现:
def _emit_size_impl(ctx): in_file = ctx.file.file out_file = ctx.actions.declare_file("%s.pylint" % ctx.attr.name) # 获取data属性关联的所有文件 data_files = ctx.files.data ctx.actions.run_shell( # 合并所有输入文件,Bazel会自动将列表内所有文件准备到沙箱 inputs = [in_file] + data_files, outputs = [out_file], # 命令中如果需要访问data文件,直接通过<变量>.path获取路径即可 command = "wc -c '%s' > '%s'" % (in_file.path, out_file.path), ) return [ DefaultInfo( files = depset([out_file]), # 可选:向上层规则传递data运行依赖 runfiles = ctx.runfiles(files = data_files) ) ] emit_size = rule( implementation = _emit_size_impl, attrs = { "file": attr.label( mandatory = True, allow_single_file = True, ), "data": attr.label_list(allow_files = True), }, )
进阶注意事项
如果data依赖包含其他规则产出的可执行文件、或自身带有运行时依赖,直接用ctx.files.data会漏掉传递性依赖,需要从依赖的DefaultInfo中收集完整的文件和runfiles:
data_inputs = [] for dep in ctx.attr.data: # 收集依赖本身的产出文件 data_inputs.extend(dep[DefaultInfo].files.to_list()) # 收集依赖的传递性运行文件 data_inputs.extend(dep[DefaultInfo].default_runfiles.files.to_list())
收集完成后再将data_inputs合并入action的inputs参数即可。
内容的提问来源于stack exchange,提问作者edc
相关产品推荐
相关产品推荐

