Bazel 如何编写genrule以应用修补程序

Bazel 如何编写genrule以应用修补程序,bazel,Bazel,我正在尝试为其中一个包在bazel BUILD中编写genrule。其目的是规则必须在包源上应用一个修补程序。我写的如下- genrule( name = "patching_rule", srcs = ["Package"], outs = ["test_output.txt"], cmd = "cd $(location Package); patch -p0 < /tmp/mypatch.patch", ) genrule( name=“修补规则”,

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

genrule(
    name = "patching_rule",
    srcs = ["Package"],
    outs = ["test_output.txt"],
    cmd = "cd $(location Package); patch -p0 < /tmp/mypatch.patch",
)
genrule(
name=“修补规则”,
srcs=[“包”],
outs=[“test_output.txt”],
cmd=“cd$(位置包);patch-p0
阅读bazel构建文档后,我知道“outs”是必填字段。然而,我的补丁肯定不会产生任何效果。它只需要在包源代码中进行2-3行代码更改。我不能保持“outs”为空,也不能在那里添加虚拟文件。谁能帮我解决这个问题吗

提前感谢,,
尼希达

如评论中所述,如果希望在genrule中进行修补,则需要将要修补的源声明为输入,并将生成的源声明为输出,genrule和Bazel build通常不允许修改输入树

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

load("//:local_patched_repository.bzl", "local_patched_repository")
local_patched_repository(
    name = "org_tensorflow",
    path = "tensorflow",
    patch = "//:mypatch.patch",
)
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)
使用
BUILD
文件(可以为空),
mypatch.patch
local\u patched\u repository.bzl
位于
工作区
文件旁边。现在,
local\u patched\u repository.bzl
的内容如下所示:

load("//:local_patched_repository.bzl", "local_patched_repository")
local_patched_repository(
    name = "org_tensorflow",
    path = "tensorflow",
    patch = "//:mypatch.patch",
)
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)
def_impl(rctxt):
path=rtcxt.attr.path
#如果该路径是相对的,那么要获得实际路径就有点难看。
如果路径[0]!="/":
#path(Label(“/:BUILD”))将返回生成文件的路径
#在当前工作区中,因此获取dirname将获取路径
#相对于工作区。
path=rctxt.path(标签(“/:BUILD”).dirname+“/”+path
#复制存储库
结果=rctxt.execute([“cp”、“-fr”、path+“/*”、rctxt.path())
if result.return_code!=0:
失败(“未能复制%s(%s)”%(rctxt.attr.path,result.return\u代码))
#现在修补存储库
patch_file=str(rctxt.path(rctxt.attr.patch).realpath)
结果=rctxt.execute([“bash”、“-c”、“patch-p0<”+patch_文件])
if result.return_code!=0:
失败(“未能修补(%s):%s”%(result.return\u代码,result.stderr))
本地\u修补的\u存储库=存储库\u规则(
实现=_impl,
属性={
“路径”:属性字符串(强制=True),
“补丁”:属性标签(强制=真)
},
本地=真)
当然,这是一个快速的实现,它有一个缺点:
local=True
将使此存储库被大量重新计算,如果修补速度慢,您可能希望删除它(这意味着我们不会看到tensorflow存储库中的文件发生更改)。除非你改变一个文件,除非你碰到一个bazel错误,否则它不会正常重建

如果要替换
http\u存储库
,也可以通过替换
cp
(但tensorflow仍需要一些修改。/configure工作,使其与
http\u存储库
不兼容)


编辑:

您能再解释一下为什么要修补输入源吗?那棵打过补丁的树将如何使用?一般来说,Bazel不允许修改输入源。此修补程序将应用于外部依赖项。我实际上在尝试建立tensorflow。Tensorflow确实为我构建,没有任何更改。但在构建过程中,我想在它的一个依赖项上应用一个补丁,然后下载并放入$HOME/.cache/bazel/_bazel_nishidha/9002cca31b627e38c01a15159b8ff61f/execroot/org_tensorflow/external。Tensorflow有一个用于该依赖项的构建文件,我正在尝试编写一个genrule来对其应用补丁。哦,好的,你可以使用自定义的外部存储库,我今天晚些时候会给出完整的答案。好的……谢谢你Damien。谢谢你Damien。我试试看。对不起,我刚才不清楚。tensorflow是我要建立的主要回购/来源。我正在尝试修补它下载的eigen。我会试试你的答案。在这种情况下,对于eigen,你最好使用下一部分提到的下载和摘录。我已经按照建议做了更改。但是现在,我得到了下面的错误-
error:/home/nishidha/pkgbuild/tensorflow/tensorflow/third_party/eigen3/BUILD:14:1:没有这样的包“@eigen_archive//”:被“//third_party/eigen3:eigen3”引用。
不知何故,我认为,本地的补丁_存储库没有被识别,因为它,eigen_归档被称为“没有这样的包”。如果我使用现有的定制回购规则“临时解决方案\u http\u归档”,而不是本地\u修补的\u存储库,它就可以工作。我错过什么了吗?我也检查了其他地方,但没有发现任何线索。最后我让它工作了。问题在于在_impl()函数中形成“cmd”的方式。非常感谢Damien的大力帮助。