Bazel自定义规则执行失败:print_message.sh文件缺失求修复
问题:Bazel规则执行时输出文件未创建的修复方案
问题背景
我编写了一个包含两个动作的Bazel规则:
- 动作1:基于模板生成脚本
create_a_file.sh - 动作2:执行生成的脚本,创建目标文件
print_message.sh
执行bazel run时触发错误,提示print_message.sh未被创建。
错误日志
$> bazel run //rules/test_rule/examples:gen_script --subcommands --verbose_failures ✔ 16:23:42 Starting local Bazel server and connecting to it... INFO: Analyzed target //rules/test_rule/examples:gen_script (5 packages loaded, 7 targets configured). INFO: Found 1 target... SUBCOMMAND: # //rules/test_rule/examples:gen_script [action 'Action rules/test_rule/examples/print_message.sh', configuration: 6167a43bee81d7c4ceebdf8986e0027b728c609e76e2c99eb3032efb76afa9e5, execution platform: @local_config_platform//:host] (cd /home/ryan/.cache/bazel/_bazel_ryan/7935e4c8c361f40ea6fa5552c32b5ad7/execroot/ruletest_0 && \ exec env - \ bazel-out/k8-fastbuild/bin/rules/test_rule/examples/create_a_file.sh) # Configuration: 6167a43bee81d7c4ceebdf8986e0027b728c609e76e2c99eb3032efb76afa9e5 # Execution platform: @local_config_platform//:host ERROR: /home/.../ruletest_0/rules/test_rule/examples/BUILD:4:11: output 'rules/test_rule/examples/print_message.sh' was not created ERROR: /home/.../ruletest_0/rules/test_rule/examples/BUILD:4:11: Action rules/test_rule/examples/print_message.sh failed: not all outputs were created or valid Target //rules/test_rule/examples:gen_script failed to build INFO: Elapsed time: 1.921s, Critical Path: 0.04s INFO: 5 processes: 4 internal, 1 linux-sandbox. FAILED: Build did NOT complete successfully FAILED: Build did NOT complete successfully
排查结果
检查Bazel动作结果存储路径发现:create_a_file.sh的符号链接正常,但print_message.sh的符号链接指向不存在的文件,推测文件被创建在错误路径或执行后被清理:
$> pwd /home/.../ruletest_0/bazel-out/k8-fastbuild/bin/rules/test_rule/examples/print_message.sh.runfiles/ruletest_0/rules/test_rule/examples/print_message.sh.runfiles/ruletest_0/rules/test_rule/examples $> ll create_a_file.sh -> /home/.../.cache/bazel/_bazel_.../7935e4c8c361f40ea6fa5552c32b5ad7/execroot/ruletest_0/bazel-out/k8-fastbuild/bin/rules/test_rule/examples/create_a_file.sh // 正常的符号链接 print_message.sh -> /home/.../.cache/bazel/_bazel_.../7935e4c8c361f40ea6fa5552c32b5ad7/execroot/ruletest_0/bazel-out/k8-fastbuild/bin/rules/test_rule/examples/print_message.sh // 无效的符号链接,找不到对应文件
相关代码
Bazel规则文件
# this rule creates a file def _gen_script_impl(ctx): scr_name = ctx.attr._scrname file_name = ctx.attr._filename file_contents = ctx.attr._filecontents script_template = ctx.file._script_template file_creation_script = ctx.actions.declare_file(scr_name) ctx.actions.expand_template( template = script_template, output = file_creation_script, substitutions = { "{FILE_NAME}": file_name, "{FILE_CONTENTS}": file_contents, }, is_executable = True, ) created_file = ctx.actions.declare_file(file_name) ctx.actions.run( outputs = [created_file], executable = file_creation_script, ) allfiles = depset([file_creation_script] + [created_file]) runfiles = ctx.runfiles(files = [file_creation_script] + [created_file]) return [ DefaultInfo( executable = created_file, files = allfiles, runfiles = runfiles, ), ] gen_script = rule( implementation = _gen_script_impl, attrs = { "_scrname": attr.string( default = "create_a_file.sh", ), "_filename": attr.string( default = "print_message.sh", ), "_filecontents": attr.string( default = "hello?", ), "_script_template": attr.label( allow_single_file = True, default = Label("@ruletest_0//rules/test_rule/script_template:create_a_file.sh.template"), ) }, executable = True, )
脚本模板文件
#!/usr/bin/zsh # $1: file name # $2: file content function create_a_file { echo "echo $2" > $1 } create_a_file "{FILE_NAME}" "{FILE_CONTENTS}"
修复方案
核心问题是:脚本直接用文件名创建文件时,会生成在Bazel执行的execroot根目录,而非规则中created_file声明的输出路径,导致Bazel无法找到该文件。
需要修改两处:
在Bazel规则中传递输出文件的绝对路径给脚本
更新ctx.actions.run,添加arguments参数传递created_file的完整路径:ctx.actions.run( outputs = [created_file], executable = file_creation_script, arguments = [created_file.path], # 传递输出文件的完整路径 )修改脚本模板,使用传入的路径创建文件
调整模板逻辑,使用第一个参数作为文件路径,同时移除规则中{FILE_NAME}的替换项:#!/usr/bin/zsh # $1: 输出文件的完整路径 # $2: 文件内容 function create_a_file { echo "echo $2" > "$1" } create_a_file "$1" "{FILE_CONTENTS}"对应规则中的
expand_template修改:ctx.actions.expand_template( template = script_template, output = file_creation_script, substitutions = { "{FILE_CONTENTS}": file_contents, # 移除{FILE_NAME}的替换逻辑 }, is_executable = True, )
验证
修改后重新执行bazel run,Bazel会正确识别生成的print_message.sh文件,错误消失。
内容的提问来源于stack exchange,提问作者Grrrr
相关产品推荐
相关产品推荐

