使用bazel genrule添加外部依赖项失败,并显示错误“没有输出的Genrules没有意义”。

时间:2019-01-12 02:44:58

标签: bazel

我正在尝试使用一种原语来获取并建立外部依赖。设置如下。

[root] / WORKSPACE

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "gsl",
    url = "https://mirror.freedif.org/GNU/gsl/gsl-latest.tar.gz",
    build_file = '@//thirdparty:gsl.BUILD',
)

[root] /thirdparty/gsl.BUILD

genrule(
    name = "gsl_genrule",
    srcs = glob([
      "gsl-2.5/**/*.c",
      "gsl-2.5/**/*.h",
    ]),
    outs = glob([
      "gsl-2.5/install/lib/*.so",
      "gsl-2.5/install/include/**/*.h",
    ]),
    cmd = "mkdir install && ./configure --prefix=`pwd`/install && make -j && make install",
)

cc_library(
    name = "gsl",
    srcs = [":gsl_genrule"],
    visibility = ["//visibility:public"],
)

[root] / src / BUILD

cc_binary(
    name = "hello",
    srcs = [
        "hello.cc",
    ],
    deps = [
        "@gsl//:gsl"
    ],
)

此外,我在[Root] / thirdparty中有一个空的BUILD文件,可以防止bazel无法找到gsl.BUILD的错误。 [1]

当我运行它时,genrule失败,如下所示。

$  bazel build -c dbg --sandbox_debug //src:*
INFO: Invocation ID: a698121f-fc3f-449a-9e36-eb2a5f59e06b
INFO: SHA256 (https://mirror.freedif.org/GNU/gsl/gsl-latest.tar.gz) = 0460ad7c2542caaddc6729762952d345374784100223995eb14d614861f2258d
ERROR: /home/buddhika/.cache/bazel/_bazel_buddhika/3fbc2046978475f6bf9fc76463e16ae5/external/gsl/BUILD.bazel:8:12: in outs attribute of genrule rule @gsl//:gsl_genrule: Genrules without outputs don't make sense
ERROR: Analysis of target '//src:hello.dwp' failed; build aborted: Analysis of target '@gsl//:gsl_genrule' failed; build aborted
INFO: Elapsed time: 11.261s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (3 packages loaded, 1689 targets configured)

我有由上面gsl.BUILD文件中所示的指定类型生成的输出。知道我在做什么错吗?

[1] https://github.com/bazelbuild/bazel/issues/6873

1 个答案:

答案 0 :(得分:1)

我将首先关注您的问题(但是您可能要重新考虑将生成的一部分委派给自动工具的计划,并依靠慷慨大方地使用globbing)。错误消息实际上包含您的答案:

bazel在分析构建设置时,将(按照指示)查找所有(现有)"gsl-2.5/install/lib/*.so""gsl-2.5/install/include/**/*.h"文件,并且(在分析时)找不到任何文件。即outs是一个空列表,就bazel而言,您的规则的确不会产生任何输出,从而使它毫无意义。

您可以列出您知道在那里的实际文件。或者,您必须使用与TreeArtifacts一起使用的自定义规则(将TreeArtifacts与(所有)库和标头一起吐出)。您还可以预先构建依赖关系,并依赖于生成的归档文件/树。或“ bazelify”其构建。 (根据其性质和使用方式,我可能更喜欢后两种选择之一。)


编辑:对评论进行更详细的解释。

Bazel首先必须分析并确定构建树的外观。在glob()中使用outs(基本上没有意义)时,它将在分析之前之前outs定义为全局文件列表(在分析阶段)规则已执行。

outs = ["concatenated.txt"]

很好,因为它说规则输出恰好是一个文件concatenated.txt。但是:

outs = glob(["*.txt"])

甚至:

outs = glob(["concatenated.txt"])

与以下相同:

outs = []

因为在确定要构建的内容时(glob()开始使用时),没有文件匹配(您可以将其认为是:在构建之前告诉构建结果将是{ {1}}或find返回输出树,但现在在我实际构建之前)。断开连接是,您似乎希望ls定义规则运行后(在构建步骤已完成的情况下)后的操作,但前提是用户必须先了解之前它执行任何规则,哪个步骤会产生什么结果,然后反过来需要做什么才能建立请求的目标。

TreeArtifacts和declare_directory与您在上面所说的相近,因为它告诉bazel根据规则,将存在一个目录(其中包含内容)。

您还可以逐字列出所有outs*.so文件,因为它们是由构建产生的,这也将为您解决此问题。

对于预构建,我的意思是仅在bazel之外进行编译,打包结果,并从bazel构建中引用包含库和接口描述(标题)的存档。在以下情况下,该选项通常可以使用:

  • 您的依赖关系不会经常更新
  • 您不必担心支持范围广泛甚至未知的目标系统

否则,值得将其构建“ Bazelizing”以使其成为您自己的树构建的一部分。