我的情况是我有一个"父母" Bazel项目包含一些shell脚本&宏。该项目必须由" Child"项目。最小的工作"重现问题的示例定义如下:
目录结构
├── Child
│ ├── BUILD
│ └── WORKSPACE
└── Parent
├── a_command.bzl
├── a_script.sh
├── BUILD
└── WORKSPACE
父项目文件
父/ a_script.sh
#!/bin/bash
date
父/ a_command.bzl
def a_command(name):
native.genrule(
name = name,
srcs = [],
outs = [name+".txt"],
cmd = "$(location :a_script_sh) > $@",
tools = [":a_script_sh"],
)
父/ BUILD
sh_binary(
name = "a_script_sh",
srcs = ["a_script.sh"],
visibility = ["//visibility:public"],
)
Parent / WORKSPACE
# empty file
子项目文件
儿童/ WORKSPACE
local_repository(
name = "Parent",
path = "../Parent/",
)
儿童/ BUILD
load("@Parent//:a_command.bzl","a_command")
# Uncomment me for a working solution
# alias(name="a_script_sh",actual="@Parent//:a_script_sh")
a_command("use_script")
现在我的问题
如果我输入子项目目录
bazel build //...
我得到了
INFO: Found 1 target...
ERROR: missing input file '//:a_script_sh'.
ERROR: PATH/Child/BUILD:5:1: //:use_script: missing input file '//:a_script_sh'.
Target //:use_script failed to build
Use --verbose_failures to see the command lines of failed build steps.
ERROR: PATH/Child/BUILD:5:1 1 input file(s) do not exist.
INFO: Elapsed time: 0.162s, Critical Path: 0.00s
现在,如果我取消注释该行
alias(name="a_script_sh",actual="@Parent//:a_script_sh")
在 Child / BUILD 文件中,一切正常:
INFO: Found 2 targets...
INFO: Elapsed time: 0.191s, Critical Path: 0.03s
文件 use_script.txt 正确生成到 Child / bazel-genfiles 目录中。
我的问题是:
是否使用
alias(name="a_script_sh",actual="@Parent//:a_script_sh")
是正确做事的方式吗?
我期待解决这种依赖性 Bazel的工作。
我没想到必须明确重新定义 a_script.sh 文件所在的位置。我认为这很笨拙,多余且容易出错。
我怀疑我没有以正确的方式做事,我会非常感谢那些能够清楚地向我们解释如何正确行事的人。
答案 0 :(得分:2)
首先,感谢您提供清晰彻底的责备指示!
你发现了一个非常有趣的场景!然而一切都按预期工作。
a_command
中的{p> Parent/a_command.bzl
用tools=[":a_script_sh"]
包含了一个genoule。这是相对于当前包的相对标签,其中" current"是使用宏的包,而不是声明它的位置。因此,Child的BUILD文件必须声明一个" a_script_sh" target(具有此名称的任何目标),该示例将起作用。
在glob
的情况下,这种行为更有意义:如果Skylark宏用srcs=glob([**])
包装规则,宏应该从当前包中获取文件(使用宏的地方),不是外国的(声明宏的地方)。
除了向child / BUILD添加文件组之外,我还稍微修改了genrule以打印" a_script_sh"的路径。而不是执行它:
parent/a_command.bzl
:
def a_command(name):
native.genrule(
name = name,
srcs = [],
outs = [name+".txt"],
cmd = "echo $(location :a_script_sh) > $@", # modified
tools = [":a_script_sh"],
)
child/BUILD
:
load("@Parent//:a_command.bzl","a_command")
# Uncomment me for a working solution
# alias(name="a_script_sh",actual="@Parent//:a_script_sh")
a_command("use_script")
filegroup(name = 'a_script_sh', srcs = ['BUILD']) # added
我无法找到任何方法来确保宏始终使用父包//:a_script_sh
目标。宏不应该在标签前面加上存储库名称(例如"@Parent//:a_script_sh"
),因为不能保证此存储库将被绑定为" Parent"。
我找到解决此问题的唯一方法是像这样注入tools
依赖项:
parent/a_command.bzl
:
def a_command(name, tools):
native.genrule(
name = name,
srcs = [],
outs = [name+".txt"],
cmd = "echo $(location %s) > $@" % tools['a_script_sh'],
tools = [tools['a_script_sh']],
)
child/BUILD
:
load("@Parent//:a_command.bzl","a_command")
a_command(
"use_script",
tools = {"a_script_sh": "@Parent//:a_script_sh"},
)