如何编写规则以应用补丁

How to write a genrule to apply a patch

我正尝试在 bazel BUILD 中为其中一个包编写一个 genrule。目的是规则必须在包源上应用一个补丁。我写的如下 -

genrule(
    name = "patching_rule",
    srcs = ["Package"],
    outs = ["test_output.txt"],
    cmd = "cd $(location Package); patch -p0 < /tmp/mypatch.patch",
)

看了bazel BUILD文档,才知道"outs"是必填字段。但是,我的补丁肯定不会生成任何东西。它只是 2-3 行代码更改,它将在包源代码中进行。我不能让 "outs" 为空,也不能在那里添加虚拟文件。谁能帮我解决这个问题?

提前致谢, 西达

✿如评论中所述,如果您希望在 genrule 中打补丁,则需要将要打补丁的源声明为输入,并将生成的源声明为输出,genrule 和 Bazel build 不允许修改输入树一般。

但是,由于此特定案例用于修补外部存储库 (TensorFlow),您可以使用自定义实现替换 WORKSPACE 文件中正在使用的任何存储库(可能是 local_repository) (我们将其命名为 local_patched_repository),因此 WORKSPACE 文件部分将如下所示:

load("//:local_patched_repository.bzl", "local_patched_repository")
local_patched_repository(
    name = "org_tensorflow",
    path = "tensorflow",
    patch = "//:mypatch.patch",
)

有一个BUILD文件(可以为空),mypatch.patchlocal_patched_repository.bzl紧挨着WORKSPACE文件。现在 local_patched_repository.bzl 的内容看起来像:

def _impl(rctxt):
  path = rtcxt.attr.path
  # This path is a bit ugly to get the actual path if it is relative.
  if path[0] != "/":
    # rctxt.path(Label("//:BUILD")) will returns a path to the BUILD file
    # in the current workspace, so getting the dirname get the path
    # relative to the workspace.
    path = rctxt.path(Label("//:BUILD")).dirname + "/" + path
  # Copy the repository
  result = rctxt.execute(["cp", "-fr", path + "/*", rctxt.path()])
  if result.return_code != 0:
    fail("Failed to copy %s (%s)" % (rctxt.attr.path, result.return_code))
  # Now patch the repository
  patch_file = str(rctxt.path(rctxt.attr.patch).realpath)
  result = rctxt.execute(["bash", "-c", "patch -p0 < " + patch_file])
  if result.return_code != 0:
    fail("Failed to patch (%s): %s" % (result.return_code, result.stderr))

local_patched_repository = repository_rule(
    implementation=_impl,
    attrs={
        "path": attr.string(mandatory=True),
        "patch": attr.label(mandatory=True)
    },
    local = True)

当然这是一个快速的实现并且有一个陷阱:local = True 会使这个存储库被重新计算很多,如果修补很慢,你可能想要删除它(这意味着我们赢了'查看 tensorflow 存储库中文件的更改)。除非您更改文件,否则它不会正常重建,除非您遇到 bazel 错误。

如果你确实想替换 http_repository,你也可以用 rctx.download_and_extract 替换 cp(但 tensorflow 仍然需要一些修改,./configure 工作,使其与 http_repository).

编辑:A patch to patch on the fly the eigen http_repository on TensorFlow