如何使用 Bazel link 一个 C++ 程序到 NTL 库

How to link a C++ program to the NTL library using Bazel

我想使用 Bazel 构建一个链接到一些外部库的 C++ 项目,例如 NTL。但是,我找不到让 Bazel 构建任何包含 NTL 的程序的方法。这是一个例子。考虑以下文件结构:

/project-root
 |__main
 |  |__BUILD
 |  |__example.cc
 | 
 WORKSPACE

其中 WORKSPACE 只是我项目根目录下的一个空文件。 example.cc的内容是:

#include <iostream>

int main()
{
  int a = 5;

  std::cout << "a = " << a << std::endl;

  return 0;
}

BUILD的内容是:

load("@rules_cc//cc:defs.bzl", "cc_binary")

cc_binary(
    name = "example",
    srcs = ["example.cc"],
)

我构建的项目如下:

bazel build //main:example

我得到:

INFO: Analyzed target //main:example (38 packages loaded, 260 targets configured).
INFO: Found 1 target...
Target //main:example up-to-date:
bazel-bin/main/example
INFO: Elapsed time: 5.175s, Critical Path: 0.58s
INFO: 6 processes: 4 internal, 2 darwin-sandbox.
INFO: Build completed successfully, 6 total actions

然后我运行:

./bazel-bin/main/example

哪个returns:

a = 5

一切正常。但是,如果我包含 NTL 库,我将无法构建项目。考虑以下对 example.cc

的更新
#include <iostream>
#include <NTL/ZZ.h>

int main()
{
  int a = 5;
  NTL::ZZ b = NTL::ZZ(13);

  std::cout << "a = " << a << std::endl;
  std::cout << "b = " << b << std::endl;

  return 0;
}

如果我想直接编译example.cc,我会执行以下命令:

g++ main/example.cc -o main/example --std=c++11 -lntl

但是,我想使用 Bazel 来完成(因为我必须针对不同的目标构建,我将使用 Google Test 进行测试,以及其他一些让我想尝试 Bazel 的原因.)

根据这个 post,我可以通过在我的 BUILD 文件中添加 linkopts 来做我想做的事:

load("@rules_cc//cc:defs.bzl", "cc_binary")

cc_binary(
    name = "example",
    srcs = ["example.cc"],
    linkopts = ["-lntl"],
)

但是,当我尝试构建它时,我得到:

ERROR: /Users/.../bazel_example/main/BUILD:3:10: Compiling main/example.cc failed: (Aborted): wrapped_clang_pp failed: error executing command external/local_config_cc/wrapped_clang_pp '-D_FORTIFY_SOURCE=1' -fstack-protector -fcolor-diagnostics -Wall -Wthread-safety -Wself-assign -fno-omit-frame-pointer -O0 -DDEBUG '-std=c++11' ... (remaining 31 arguments skipped)

Use --sandbox_debug to see verbose messages from the sandbox
main/example.cc:3:10: fatal error: 'NTL/ZZ.h' file not found
#include <NTL/ZZ.h>
     ^~~~~~~~~~
1 error generated.
Error in child process '/usr/bin/xcrun'. 1
Target //main:example failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 3.833s, Critical Path: 0.39s
INFO: 5 processes: 5 internal.
FAILED: Build did NOT complete successfully

与我之前提到的 post 相同,讨论了通过将项目所需的任何库导入到项目中的替代方案。我看到有人建议直接在 Bazel 管理的项目中包含库 headers 的路径。

我想知道是否有一种方法可以在仅“标记”NTL 库的同时使用 Bazel 成功构建项目,以便我可以在我的项目中使用它。

我特别指的是 NTL 库,但这是我对系统中可用的任何其他外部库的理想方法。

我让 Bazel 来构建我的项目,并按照此 answer. Refer to this link for the specifics. However, the referred solution was not enough for the particular case of the NTL library. The "problem" is that NTL uses GMP by default 中的步骤 link 到 NTL。当我看到由于 Bazel“无法识别”GMP 而导致构建失败时,我有点担心。一个库可能有很多依赖项,并且为了让一个库正常工作而解决每个依赖项可能很麻烦。

谢天谢地,唯一需要的额外步骤是申请 GMP 与我申请 NTL 的相同配置。

我修改了 BUILD 文件,包括编译项目所需的依赖项:

load("@rules_cc//cc:defs.bzl", "cc_binary")

cc_binary(
    name = "example",
    srcs = ["example.cc"],
    deps = ["@ntl//:ntl_", "@gmp//:gmp_"],
)

然后我创建了“dependencies”目录并将两个文件放在那里。一种是 BUILD.ntl,内容如下:

cc_library(
    name = "ntl_",
    srcs = glob(["lib/*.dylib"] + ["lib/*.a"]),
    hdrs = glob(["include/NTL/*.h"]),
    strip_include_prefix = "include/",
    visibility = ["//visibility:public"]
)

和BUILD.gmp

cc_library(
    name = "gmp_",
    srcs = glob(["lib/*.dylib"] + ["lib/*.a"]),
    hdrs = glob(["include/*.h"]),
    strip_include_prefix = "include/",
    visibility = ["//visibility:public"]
)

最后,我将以下内容添加到之前空的 WORKSPACE 文件中:

new_local_repository(
  name = "ntl",
  path = "/usr/local/var/homebrew/linked/ntl",
  build_file = "dependencies/BUILD.ntl",
)

new_local_repository(
  name = "gmp",
  path = "/usr/local/var/homebrew/linked/gmp",
  build_file = "dependencies/BUILD.gmp",
)

显然,new_local_repository下的路径可以是platform/machine/user具体的。我使用 Homebrew 这些路径安装了 NTL 和 GMP。

我想要一个尽可能“无缝”的解决方案。在不知道任何其他“更清洁”的方法的情况下,我会坚持这个。

现在我只需要清理之前失败的构建:

bazel clean

并重新构建它:

bazel build //main:example

所以我得到:

INFO: Analyzed target //main:example (40 packages loaded, 391 targets configured).
INFO: Found 1 target...
Target //main:example up-to-date:
  bazel-bin/main/example
INFO: Elapsed time: 5.128s, Critical Path: 1.54s
INFO: 129 processes: 127 internal, 2 darwin-sandbox.
INFO: Build completed successfully, 129 total actions

当我运行

./bazel-bin/main/example

我看到了预期的结果:

a = 5
b = 13