如何使 bazel `sh_binary` 目标依赖于其他二进制目标?

psi*_*gen 9 bazel

我已经设置了 bazel 来构建许多执行各种数据库维护任务的 CLI 工具。每个都是一个py_binarycc_binary目标,从命令行调用,并带有指向某个数据文件的路径:它处理该文件并将结果存储在数据库中。

现在,我需要创建一个依赖包,其中包含调用这些 CLI 工具来执行特定于应用程序的数据库操作的数据文件和 shell 脚本。

但是,似乎没有办法依赖于仅包含目标和数据文件的新包中的现有py_binarycc_binary目标sh_binary。尝试这样做会导致如下错误:

ERROR: /workspace/shbin/BUILD.bazel:5:12: in deps attribute of sh_binary rule //shbin:run: py_binary rule '//pybin:counter' is misplaced here (expected sh_library)
Run Code Online (Sandbox Code Playgroud)

有没有办法从 shell 脚本调用/依赖现有的 bazel 二进制目标sh_binary

我在这里实现了一个完整的例子:https : //github.com/psigen/bazel-mixed-binaries


笔记:

我不能用py_libraryandcc_library代替py_binaryand cc_binary。这是因为(a)我需要调用两种语言的混合来处理我的数据文件,并且(b)这些工具来自上游存储库,它们已经被设计为 CLI 工具。

我也无法将所有数据文件放入 CLI 工具包中——有多个特定于应用程序的包,它们不能混合使用。

Lás*_*zló 12

您可以创建一个 genrule 来运行这些工具作为构建的一部分,或者创建一个 sh_binary 来通过data属性依赖于这些工具并运行它们。

规则方法

这是更简单的方法,可让您将工具作为构建的一部分运行。

genrule(
    name = "foo",
    tools = [
        "//tool_a:py",
        "//tool_b:cc",
    ],
    srcs = [
        "//source:file1",
        ":file2",
    ],
    outs = [
        "output_file1",
        "output_file2",
    ],
    cmd = "$(location //tool_a:py) --input=$(location //source:file1) --output=$(location output_file1) && $(location //tool_b:cc) < $(location :file2) > $(location output_file2)",
)
Run Code Online (Sandbox Code Playgroud)

sh_binary 方法

这更复杂,但允许您将 sh_binary 作为构建的一部分(如果它在 a 中genrule.tools,类似于之前的方法)或在构建之后(从 under bazel-bin)运行。

sh_binary你必须依赖于数据的工具:

sh_binary(
    name = "foo",
    srcs = ["my_shbin.sh"],
    data = [
        "//tool_a:py",
        "//tool_b:cc",
    ],
)
Run Code Online (Sandbox Code Playgroud)

然后,sh_binary您必须使用 Bazel 内置的所谓“Bash 运行文件库”来查找二进制文件的运行时路径。这个库的文档在它的源文件中

这个想法是:

  1. sh_binary 必须依赖于特定的目标
  2. 您必须将一些样板代码复制粘贴到 sh_binary 的顶部(原因在此处描述)
  3. 然后您可以使用该rlocation函数查找二进制文件的运行时路径

例如,您my_shbin.sh可能看起来像这样:

#!/bin/bash
# --- begin runfiles.bash initialization ---
...
# --- end runfiles.bash initialization ---

path=$(rlocation "__main__/tool_a/py")
if [[ ! -f "${path:-}" ]]; then
  echo >&2 "ERROR: could not look up the Python tool path"
  exit 1
fi
$path --input=$1 --output=$2
Run Code Online (Sandbox Code Playgroud)

__main__在rlocation路径参数是工作区的名称。由于您的WORKSPACE文件没有定义工作区名称的“工作区”规则,因此 Bazel 将使用默认工作区名称,即__main__.

  • 如果您尝试使用第二种方法,请确保您复制粘贴到 shell 脚本中的样板来自 master,自这篇文章首次撰写以来,它已经发生了一些变化。 (2认同)

ron*_*man 8

一个干净的方法是使用argsand$(location)

内容BUILD

py_binary(
    name = "counter",
    srcs = ["counter.py"],
    main = "counter.py",
)

sh_binary(
    name = "run",
    srcs = ["run.sh"],
    data = [":counter"],
    args = ["$(location :counter)"],
)
Run Code Online (Sandbox Code Playgroud)

(您的工具)的内容counter.py

print("This is the counter tool.")
Run Code Online (Sandbox Code Playgroud)

run.sh(您的 bash 脚本)的内容:

#!/bin/bash
set -eEuo pipefail

counter="$1"
shift

echo "This is the bash script, about to call the counter tool."
"$counter"
Run Code Online (Sandbox Code Playgroud)

下面是一个演示,展示了调用 Python 工具的 bash 脚本:

$ bazel run //example:run 2>/dev/null
This is the bash script, about to call the counter tool.
This is the counter tool.
Run Code Online (Sandbox Code Playgroud)

还值得一提的是这个注释(来自文档):

当您在 bazel 外部运行目标时(例如,通过手动执行 bazel-bin/ 中的二进制文件),不会传递参数。


Fre*_*oen 5

对我来说,一个更简单的方法是cc_binary在该data部分中添加作为依赖项。在prefix/BUILD

cc_binary(name = "foo", ...)
sh_test(name = "foo_test", srcs = ["foo_test.sh"], data = [":foo"])
Run Code Online (Sandbox Code Playgroud)

里面foo_test.sh,工作目录不同,所以需要找到合适prefix的二进制文件

#! /usr/bin/env bash

executable=prefix/foo

$executable ...
Run Code Online (Sandbox Code Playgroud)