2017-06-12 59 views
1

我在这个场景中有一个“Parent”Bazel项目,其中包含一些shell脚本&宏。该项目必须由“儿童”项目重复使用。最小的 “工作” 的例子来重现问题定义如下:为父项目和子项目导出的shell脚本

目录结构

├── 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) > [email protected]", 
     tools = [":a_script_sh"], 
    ) 

父/ BUILD

sh_binary(
    name = "a_script_sh", 
    srcs = ["a_script.sh"], 
    visibility = ["//visibility:public"], 
) 

父/工作区

# empty file 

儿童的项目文件

儿童/工作区

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") 
儿童

/BUILD文件,一切正常:

INFO: Found 2 targets... 
INFO: Elapsed time: 0.191s, Critical Path: 0.03s 

而文件use_script.txt已正确生成儿童/ bazel-genfiles目录。

我的问题是

是否使用的

alias(name="a_script_sh",actual="@Parent//:a_script_sh") 

正确的方式做的事情吗?

我曾期待这是巴泽尔的工作,以解决这种依赖

我没想到有明确重新定义其中a_script.sh文件。我认为这很尴尬,多余且容易出错。

我怀疑我没有做正确的事情,我会非常感谢任何能清楚地向我们解释如何正确做到这一点的人。

回答

3

首先,感谢您清楚彻底的repro指令!

您发现了一个非常有趣的场景!然而,一切都按预期工作。

a_command in Parent/a_command.bzltools=[":a_script_sh"]包装了一个genrule。这是一个相对于当前包的相对标签,其中“current”是使用宏的包,而不是声明的位置。因此,Child的BUILD文件必须声明一个“a_script_sh”目标(任何具有此名称的目标),该示例将起作用。

这种行为在glob的情况下更具有意义:如果Skylark宏使用srcs=glob([**])包装规则,宏应该从当前包(使用宏的地方)中获取文件,而不是外部文件(其中宏被声明)。

在添加一个文件组儿童/ 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) > [email protected]", # 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 t ARGET。该宏不应该为标签添加一个存储库名称(例如"@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) > [email protected]" % 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"}, 
) 
+0

感谢您的积极反馈和解释。正如你自己写的那样:宏被扩展到使用它的地方(它毕竟只是一个宏:-)),并且我们不能在//::a_script_sh前缀,因为我们不知道Child项目中的未来边界。就像我在学习巴泽尔一样,我担心我错过了什么......再次感谢 –