【问题标题】:How do I make a bazel `sh_binary` target depend on other binary targets?如何使 bazel `sh_binary` 目标依赖于其他二进制目标?
【发布时间】:2018-11-25 23:19:01
【问题描述】:

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

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

但是,似乎没有办法从仅包含 sh_binary 目标和数据文件的新包中依赖现有的 py_binarycc_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 工具包中——有多个特定于应用程序的包,它们不能混合使用。

【问题讨论】:

    标签: bazel


    【解决方案1】:

    您可以创建一个 genrule 以在构建过程中运行这些工具,也可以通过 data 属性创建一个依赖于这些工具的 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 运行文件库”来查找二进制文件的运行时路径。这个库的文档是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
    

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

    【讨论】:

    • 感谢@Laszlo,第二种方法效果很好!
    • 感谢您的编辑建议psigen!显然是被拒绝了。我用 shell 脚本的错误修复编辑了原始帖子。
    • 如果您尝试使用第二种方法,请确保您复制粘贴到您的 shell 脚本中的样板是来自 master,自从第一次写这篇文章以来它已经发生了一些变化。
    【解决方案2】:

    对我来说更简单的方法是将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 ...
    

    【讨论】:

    • 这也是您可以依赖由您想在py_binarypy_library 中使用的其他目标创建的共享库的方式。
    • 这应该是公认的答案。无需为此使用 rlocation。
    【解决方案3】:

    一个干净的方法是使用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"
    

    下面是一个演示,展示了调用 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.
    

    还值得一提的是这条注释 (from the docs):

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

    【讨论】:

    • MVP 就在这里!这是唯一对我有用的解决方案,谢谢
    • 这很好用。但是,如果 sh 文件有一个已通过 pip 安装的包,例如 celery 并且您执行了一个操作,例如 celery -A xxx worker -l INFO &amp;&gt; /app/logs/celery.log &amp; ,您仍然会收到有关 celery 的错误。有没有办法让sh_binary 知道已安装的软件包?看到这个问题stackoverflow.com/questions/71602479/…
    • 你的 sh 二进制文件可以做任何它喜欢的事情,包括设置PYTHONPATH。但这会使您的构建不密封,因此您可能希望避免它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-13
    • 1970-01-01
    相关资源
    最近更新 更多