You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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无法找到该文件。

需要修改两处:

  1. 在Bazel规则中传递输出文件的绝对路径给脚本
    更新ctx.actions.run,添加arguments参数传递created_file的完整路径:

    ctx.actions.run(
        outputs = [created_file],
        executable = file_creation_script,
        arguments = [created_file.path],  # 传递输出文件的完整路径
    )
    
  2. 修改脚本模板,使用传入的路径创建文件
    调整模板逻辑,使用第一个参数作为文件路径,同时移除规则中{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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:55:32