在 Bazel 项目中包含 C++ 库

Include C++ library in Bazel project

我目前正在研究 Google's Mediapipe,它使用 Bazel 作为构建工具。该文件夹具有以下结构:

mediapipe
    ├ mediapipe
    |   └ examples
    |        └ desktop
    |             └ hand_tracking
    |                  └ BUILD
    ├ calculators
    |   └ tensor
    |        └ tensor_to_landmarks_calculator.cc
    |        └ BUILD
    └ WORKSPACE

里面还有一堆其他的文件,但是它们与这个问题无关。如果您需要它们,可以在上面链接的 git 存储库中找到它们。

我正处于可以毫无问题地构建 运行 hand_tracking 示例的阶段。现在,我想在构建中包含 cereal library,这样我就可以在 tensors_to_landmarks_calculator.cc 中使用 #include <cereal/archives/binary.hpp>。谷物库位于C:\cereal,但如果简化流程,可以移动到其他位置。

基本上,我正在寻找相当于在 Visual Studio 中添加 Additional Include Directories 路径的 Bazel。

假设它们处于默认状态,我需要如何修改 WORKSPACE 和 BUILD 文件才能将库包含在我的项目中?

不幸的是,this official doc page 只涵盖单文件库,而其他实现在构建时不断给我 File could not be found 错误。

提前致谢!

首先你必须告诉 Bazel 关于“外部”的代码 工作区。它需要知道如何找到它,如何构建它,以及 叫什么等等。这些被称为远程存储库。他们 可以是本地磁盘(在 Bazel 工作区之外),或者 实际上在另一台机器或服务器上是远程的,比如 github。这 重要的是必须向 Bazel 充分说明 它可以使用的信息。

由于大多数第三方代码不附带 BUILD.bazel 文件,您可以 需要自己提供一个并告诉 Bazel “把它当作一个 在该代码中找到构建文件。"

对于 bazel 项目之外的本地目录

将这样的存储库规则添加到您的 WORKSPACE 文件:

# This could go in your WORKSPACE file
# (But prefer the http_archive solution below)
new_local_repository(
    name = "cereal",
    build_file = "//third_party:cereal.BUILD.bazel",
    path = "<path-to-directory>",
)

("new_local_repository" 是 built-in 到 bazel)

在 Bazel WORKSPACE 区域下的某处,您还需要制作一个 cereal.BUILD.bazel 文件并将其从包中导出。我选择了一个名为 //third_party 的目录,但您可以将它放在任何地方 else,并命名为任何其他名称,只要存储库规则 为它提供了一个合适的 bazel 标签。)内容可能看起来像 这个:

# contents of //third_party/cereal.BUILD.bazel
cc_library(
    name = "cereal-lib",
    srcs = glob(["**/*.hpp"]),
    includes = ["include"],
    visibility = ["//visibility:public"],
)

Bazel 会假装这是远程“附带”的 BUILD 文件 存储库,即使它实际上是您的存储库的本地。当 Bazel 获取此远程 repostiory 代码时,它会将它和您提供的 BUILD 文件复制到其外部区域以进行缓存、构建等。

要使 //third_party:cereal.BUILD.bazel 成为目录中的有效目标,请将 BUILD.bazel 文件添加到该目录:

# contents of //third_party/BUILD.bazel

exports_files = [
    "cereal.BUILD.bazel",
]

如果不导出它,您将无法从存储库规则中引用构建文件。

本地磁盘存储库不是很便携,因为人们可能有 安装了不同的版本并且它不是很密封(使其 很难与其他人共享构建的缓存),并且需要他们将 它们在同一个地方,这种设置可能会有问题。它 如果您将其称为“C:...”

,则在混合操作系统等时也会失败

从 github 下载库的 tarball,例如

更好的方法是从github下载固定版本,例如, 让 Bazel 在其外部区域为您管理它:

http_archive(
    name = "cereal",
    sha256 = "329ea3e3130b026c03a4acc50e168e7daff4e6e661bc6a7dfec0d77b570851d5",
    urls = 
["https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.0.tar.gz"],
    build_file = "//third_party:cereal.BUILD.bazel",
)

sha256 很重要,因为它下载并计算它,与您指定的内容进行比较,并可以缓存它。以后如果本地文件的sha匹配就不会re-download了。

注意,它再次显示 build_file = //third_party:cereal.BUILD.bazel.,所有 上面 new_local_repository 中的相同内容也适用于此。确保您提供构建文件供其使用,并从您放置它的位置导出它。

*测试远程仓库设置是否正常

关于命令行问题

bazel fetch @cereal//:cereal-lib

如果我的规则不太正确,但“坏”版本仍然存在,我有时必须清除它才能重试。

bazel clean --expunge

会删除它,但可能有点矫枉过正。

终于

我们有:

  • 定义了一个名为 @cereal
  • 的远程存储库
  • 在其中定义了一个名为 cereal-lib
  • 的目标
  • 因此目标是@cereal//:cereal-lib

使用它

转到您要包含麦片的包裹,然后添加 依赖此存储库来构建要使用谷物的 c++ 代码的规则。也就是说,在您的情况下,导致构建 tensor_to_landmarks_calculator.cc 的 BUILD 规则,添加:

   deps = [
       "@cereal//:cereal-lib",
       ...
   ]

然后在您的 C++ 代码中:

#include "cereal/cereal.hpp"

应该可以了。