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

时间:2018-11-25 23:19:02

标签: bazel

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

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

但是,似乎没有一种方法可以依靠仅包含py_binary个目标和数据文件的新程序包中的现有cc_binarysh_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)

是否有一种方法可以使用sh_binary从Shell脚本调用/依赖现有的bazel二进制目标?

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


注释:

我不能使用py_librarycc_library而不是py_binarycc_binary。这是因为(a)我需要调用两种语言的混合来处理我的数据文件,而(b)这些工具来自已经设计了它们的上游存储库作为CLI工具。

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

3 个答案:

答案 0 :(得分:2)

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

Genrule方法

这是更简单的方法,可让您在构建过程中运行这些工具。

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

sh_binary方法

这更复杂,但是可以让您在构建的一部分(如果它在genrule.tools中,类似于先前的方法)或在构建之后(在bazel-bin下)运行sh_binary )。

sh_binary中,您必须取决于工具的数据:

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

然后,在sh_binary中,您必须使用Bazel内置的所谓的“ Bash运行文件库”来查找二进制文件的运行时路径。该库的文档为in its source file

想法是:

  1. sh_binary必须depend on a specific target
  2. 您必须copy-paste some boilerplate code到sh_binary的顶部(原因描述为here
  3. 然后您可以use the rlocation function查找二进制文件的运行时路径

例如,您的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

rlocation path参数中的__main__是工作空间的名称。由于您的WORKSPACE文件没有用于定义工作空间名称的“工作空间”规则,因此Bazel将使用默认的工作空间名称,即__main__

答案 1 :(得分:1)

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

cc_binary(name = "foo", ...)
sh_test(name = "foo_test", srcs = ["foo_test.sh"], data = [":foo"])

foo_test.sh内部,工作目录不同,因此您需要为二进制文件找到正确的prefix

#! /usr/bin/env bash

executable=prefix/foo

$executable ...

答案 2 :(得分:0)

一种干净的方法是使用args and $(location)

BUILD的内容:

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

sh_binary(
    name = "run",
    srcs = ["run.sh"],
    data = [":counter"],
    args = ["$(location :counter)"],
)

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

print("This is the counter tool.")

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

#!/bin/bash
set -eEuo pipefail

counter="$1"
shift

echo "This is the bash script, about to call the counter tool."
"$counter"

这是一个演示bash脚本调用Python工具的演示:

$ bazel run //example:run 2>/dev/null
This is the bash script, about to call the counter tool.
This is the counter tool.

同样值得一提的是此说明(from the docs):

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