已为父项目和子项目导出 shell 个脚本

Exported shell scripts for parent & child projects

我的场景是 "Parent" Bazel 项目,其中包含一些 shell 脚本和宏。此项目必须由 "Child" 项目重复使用。重现问题的最小 "working" 示例定义如下:

目录结构

├── Child
│   ├── BUILD
│   └── WORKSPACE
└── Parent
    ├── a_command.bzl
    ├── a_script.sh
    ├── BUILD
    └── WORKSPACE

父项目文件

Parent/a_script.sh

#!/bin/bash
date

Parent/a_command.bzl

def a_command(name):
    native.genrule(
        name = name,
        srcs = [],
        outs = [name+".txt"],
        cmd = "$(location :a_script_sh) > $@",
        tools = [":a_script_sh"],
    )

Parent/BUILD

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

Parent/WORKSPACE

# empty file

子项目文件

Child/WORKSPACE

local_repository(
    name = "Parent",
    path = "../Parent/",    
)

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

现在我的问题

如果我输入 子项目目录

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 文件所在的位置。我认为这是笨拙、多余且容易出错的。

我怀疑我做事的方式不正确,如果有人能清楚地向我们解释如何正确地做这件事,我将非常感谢。

首先,感谢您提供清晰彻底的重现说明!

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

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

这种行为在 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"},
)