首页 > 解决方案 > 如何使用 genrule 输出作为字符串来扩展 Bazel 中的模板替换?

问题描述

似乎genrule只能输出一个Target,而expand_template替换只接受string_dict,我该如何使用genrule输出来expand_template?

gen.bzl

def _expand_impl(ctx):
    ctx.actions.expand_template(
        template = ctx.file._template,
        output = ctx.outputs.source_file,
        substitutions = {
            "{version}": ctx.attr.version,
        }
    )

expand = rule(
    implementation = _expand_impl,
    attrs = {
        "version": attr.string(mandatory = True),
        "_template": attr.label(
            default = Label("//version:local.go.in"),
            allow_single_file = True,
        ),
    },
    outputs = {"source_file": "local.go"},
)

建造

load("@io_bazel_rules_go//go:def.bzl", "go_library")

filegroup(
    name = "templates",
    srcs = ["local.go.in"],
)

genrule(
    name = "inject",
    outs = ["VERSION"],
    local = 1,
    cmd = "git rev-parse HEAD",
)

load(":gen.bzl", "expand")

expand(
    name = "expand",
    version = ":inject",
)

go_library(
    name = "go_default_library",
    srcs = [
        "default.go",
        ":expand", # Keep
    ],
    importpath = "go.megvii-inc.com/brain/data/version",
    visibility = ["//visibility:public"],
)

和 local.go.in

package version

func init() {
    V = "{version}"
}

我希望 local.go.in 中的 {version} 可以被git rev-parse HEAD输出替换。

标签: bazel

解决方案


这里的问题是在分析阶段(即何时运行)必须知道的substitutions参数,这发生在运行 genrule 的命令之前(即在执行阶段)。ctx.actions.expand_template()_expand_implgit rev-parse HEAD

有几种方法可以做到这一点。最简单的是在 genrule 中做所有事情:

genrule(
    name = "gen_local_go",
    srcs = ["local.go.in"],
    outs = ["local.go"],
    local = 1,
    cmd = 'sed "s/{VERSION}/$(git rev-parse HEAD)/" "$<" > "$@"',
)

这依赖于sed主机上是否可用,但任何其他类型的可以输入一个文件、修改文本并将其输出到另一个文件的程序都可以工作。

另一种选择是结合使用--workspace_status_command 这里有更多细节: How to run a shell command at analysis time in bazel? 这种方法的优点是它避免了本地流派。


推荐阅读