正如评论中所说,如果您希望在 genrule 中进行修补,则需要将要修补的源声明为输入,并将结果源声明为输出,genrule 和 Bazel 构建通常不允许修改输入树.
但是,由于此特定情况是用于修补外部存储库 (TensorFlow),因此您可以将 WORKSPACE 文件中您正在使用的任何存储库(可能是 local_repository)替换为自定义实现(我们将其命名为 @987654325 @),所以WORKSPACE 文件部分看起来像:
load("//:local_patched_repository.bzl", "local_patched_repository")
local_patched_repository(
name = "org_tensorflow",
path = "tensorflow",
patch = "//:mypatch.patch",
)
带有BUILD 文件(可以为空),WORKSPACE 文件旁边的mypatch.patch 和local_patched_repository.bzl。现在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,也可以将 cp 替换为 rctx.download_and_extract(但 tensorflow 仍然需要进行一些修改,以使 ./configure 工作,使其与 http_repository 不兼容)。
编辑:A patch to patch on the fly the eigen http_repository on TensorFlow