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

如何在Bazel自定义规则中复用py_binary依赖,避免重复配置?

问题描述

我有一个py_binary可执行目标,希望在自定义Bazel规则中调用它。目前功能已经实现,但必须重复配置该py_binary的依赖项。有没有办法避免这种重复,自动包含py_binary的依赖?

我把问题简化成了以下示例(可通过运行//foo:main目标复现):

greet/BUILD.bazel:

py_binary(
    name = "greet",
    srcs = ["greet.py"],
    deps = ["@rules_python//python/runfiles"],
    visibility = ["//visibility:public"],
)

greet/greet.py:

from rules_python.python.runfiles import runfiles

print("hello world")

foo/BUILD.bazel:

load("//bazel:defs.bzl", "foo_binary")

foo_binary(
    name = "main",
)

bazel/BUILD.bazel:

(空文件)

bazel/defs.bzl:

def _foo_binary(ctx):
    shell_script = ctx.actions.declare_file("run.sh")
    ctx.actions.write(
        output = shell_script,
        content = """#!/bin/bash
$0.runfiles/svkj/{runtime}
""".format(runtime=ctx.executable._greet.short_path),
        is_executable = True,
    )

    return [
        DefaultInfo(
            executable = shell_script,
            runfiles = ctx.runfiles(
                files = ctx.files._greet + ctx.files.deps + ctx.files._python,
                collect_data = True
            ),
        ),
    ]

foo_binary = rule(
    implementation = _foo_binary,
    attrs = {
        "deps": attr.label_list(
            allow_files=True,
        ),
        "_greet": attr.label(
            default = "//greet:greet",
            cfg = "exec",
            executable = True,
        ),
        # TODO - Why is it necessary to add this explicitly?
        "_python": attr.label_list(
            allow_files=True,
            default = ["@python3_9//:python3", "@rules_python//python/runfiles"],
        ),
    },
    executable = True,
)

WORKSPACE:

workspace(name = "svkj")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "rules_python",
    sha256 = "5fa3c738d33acca3b97622a13a741129f67ef43f5fdfcec63b29374cc0574c29",
    strip_prefix = "rules_python-0.9.0",
    url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.9.0.tar.gz",
)

load("@rules_python//python:repositories.bzl", "python_register_toolchains")

python_register_toolchains(
    name = "python3_9",
    python_version = "3.9",
)

load("@python3_9//:defs.bzl", "interpreter")

解决方案

要自动包含py_binary的依赖,无需手动重复声明_python这类依赖项,核心是直接复用目标//greet:greet的DefaultInfo中提供的runfiles,而非手动收集文件。

修改bazel/defs.bzl如下:

def _foo_binary(ctx):
    shell_script = ctx.actions.declare_file("run.sh")
    ctx.actions.write(
        output = shell_script,
        content = """#!/bin/bash
$0.runfiles/svkj/{runtime}
""".format(runtime=ctx.executable._greet.short_path),
        is_executable = True,
    )

    # 获取_greet目标的DefaultInfo,复用它的runfiles
    greet_default_info = ctx.attr._greet[DefaultInfo]
    # 合并自定义规则的deps和_greet的runfiles
    combined_runfiles = ctx.runfiles(files = ctx.files.deps).merge(greet_default_info.default_runfiles)

    return [
        DefaultInfo(
            executable = shell_script,
            runfiles = combined_runfiles,
        ),
    ]

foo_binary = rule(
    implementation = _foo_binary,
    attrs = {
        "deps": attr.label_list(
            allow_files=True,
        ),
        "_greet": attr.label(
            default = "//greet:greet",
            cfg = "exec",
            executable = True,
        ),
        # 移除手动声明的_python依赖
    },
    executable = True,
)

原理说明

  • py_binary目标的DefaultInfo已经包含了它运行所需的所有依赖(包括Python解释器、runfiles库等),通过ctx.attr._greet[DefaultInfo]可直接获取这些信息。
  • 使用runfiles.merge()方法将自定义规则的deps和_greet的runfiles合并,无需手动重复声明依赖。
  • 移除_python属性后,规则会自动继承py_binary的所有依赖,彻底避免重复配置。

修改后运行bazel run //foo:main即可正常执行,且无需维护重复的依赖列表。

内容的提问来源于stack exchange,提问作者Steve Vermeulen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 08:37:07