如何使 bazel `sh_binary` 目标依赖于其他二进制目标?
How do I make a bazel `sh_binary` target depend on other binary targets?
我已经设置了 bazel 来构建许多执行各种数据库维护任务的 CLI 工具。每个都是一个 py_binary
或 cc_binary
目标,从命令行使用某些数据文件的路径调用:它处理该文件并将结果存储在数据库中。
现在,我需要创建一个依赖包,其中包含数据文件和 shell 调用这些 CLI 工具以执行特定于应用程序的数据库操作的脚本。
但是,似乎没有办法从仅包含 sh_binary
目标和数据文件的新包中依赖现有的 py_binary
或 cc_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 二进制目标上 call/depend?
我在这里实现了一个完整的例子:
https://github.com/psigen/bazel-mixed-binaries
备注:
我不能用 py_library
和 cc_library
代替 py_binary
和 cc_binary
。这是因为 (a) 我需要调用两种语言的混合来处理我的数据文件,并且 (b) 这些工具来自上游它们已被设计为 CLI 工具的存储库。
我也无法将所有数据文件都放入 CLI 工具包中——应用程序特定的包有多个,不能混用。
您可以为 运行 这些工具创建 genrule 作为构建的一部分,或者通过 data
属性和 [=61] 创建依赖于工具的 sh_binary =]他们是他们。
绅士法则
这是更简单的方法,让您 运行 将工具作为构建的一部分。
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 方法
这更复杂,但可以让您 运行 sh_binary 作为构建的一部分(如果它在 genrule.tools
中,类似于之前的方法)或之后构建(来自 bazel-bin
)。
在sh_binary
中你必须数据依赖工具:
sh_binary(
name = "foo",
srcs = ["my_shbin.sh"],
data = [
"//tool_a:py",
"//tool_b:cc",
],
)
然后,在 sh_binary
中,您必须使用 Bazel 内置的所谓 "Bash runfiles library" 来查找二进制文件的 运行 时间路径。该库的文档是 in its source file.
想法是:
- sh_binary 必须 depend on a specific target
- 你必须 copy-paste some boilerplate code to the top of the sh_binary (reason is described here)
- 然后你可以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= --output=
rlocation 路径参数中的__main__
是工作空间的名称。由于您的 WORKSPACE
文件中没有定义工作区名称的 "workspace" 规则,Bazel 将使用默认工作区名称,即 __main__
.
对我来说更简单的方法是在 data
部分添加 cc_binary
作为依赖项。在prefix/BUILD
cc_binary(name = "foo", ...)
sh_test(name = "foo_test", srcs = ["foo_test.sh"], data = [":foo"])
在foo_test.sh
里面,工作目录不同,所以需要为binary
找到正确的prefix
#! /usr/bin/env bash
executable=prefix/foo
$executable ...
一个干净的方法是使用 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=""
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):
The arguments are not passed when you run the target outside of bazel (for example, by manually executing the binary in bazel-bin/).
我已经设置了 bazel 来构建许多执行各种数据库维护任务的 CLI 工具。每个都是一个 py_binary
或 cc_binary
目标,从命令行使用某些数据文件的路径调用:它处理该文件并将结果存储在数据库中。
现在,我需要创建一个依赖包,其中包含数据文件和 shell 调用这些 CLI 工具以执行特定于应用程序的数据库操作的脚本。
但是,似乎没有办法从仅包含 sh_binary
目标和数据文件的新包中依赖现有的 py_binary
或 cc_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 二进制目标上 call/depend?
我在这里实现了一个完整的例子: https://github.com/psigen/bazel-mixed-binaries
备注:
我不能用 py_library
和 cc_library
代替 py_binary
和 cc_binary
。这是因为 (a) 我需要调用两种语言的混合来处理我的数据文件,并且 (b) 这些工具来自上游它们已被设计为 CLI 工具的存储库。
我也无法将所有数据文件都放入 CLI 工具包中——应用程序特定的包有多个,不能混用。
您可以为 运行 这些工具创建 genrule 作为构建的一部分,或者通过 data
属性和 [=61] 创建依赖于工具的 sh_binary =]他们是他们。
绅士法则
这是更简单的方法,让您 运行 将工具作为构建的一部分。
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 方法
这更复杂,但可以让您 运行 sh_binary 作为构建的一部分(如果它在 genrule.tools
中,类似于之前的方法)或之后构建(来自 bazel-bin
)。
在sh_binary
中你必须数据依赖工具:
sh_binary(
name = "foo",
srcs = ["my_shbin.sh"],
data = [
"//tool_a:py",
"//tool_b:cc",
],
)
然后,在 sh_binary
中,您必须使用 Bazel 内置的所谓 "Bash runfiles library" 来查找二进制文件的 运行 时间路径。该库的文档是 in its source file.
想法是:
- sh_binary 必须 depend on a specific target
- 你必须 copy-paste some boilerplate code to the top of the sh_binary (reason is described here)
- 然后你可以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= --output=
rlocation 路径参数中的__main__
是工作空间的名称。由于您的 WORKSPACE
文件中没有定义工作区名称的 "workspace" 规则,Bazel 将使用默认工作区名称,即 __main__
.
对我来说更简单的方法是在 data
部分添加 cc_binary
作为依赖项。在prefix/BUILD
cc_binary(name = "foo", ...)
sh_test(name = "foo_test", srcs = ["foo_test.sh"], data = [":foo"])
在foo_test.sh
里面,工作目录不同,所以需要为binary
prefix
#! /usr/bin/env bash
executable=prefix/foo
$executable ...
一个干净的方法是使用 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=""
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):
The arguments are not passed when you run the target outside of bazel (for example, by manually executing the binary in bazel-bin/).