我想使用 Bazel 构建一个链接到一些外部库(如 NTL)的C++项目。但是,我找不到一种方法来使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;
}
构建的内容是:
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
返回:
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 的原因。
根据这篇文章,我将能够通过在我的 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
我之前提到的同一篇文章讨论了通过将您需要的任何库导入项目的替代方案。我看到有人建议直接在 Bazel 管理的项目中包含库标题的路径。
我想知道是否有办法使用 Bazel 成功构建项目,同时只是"标记"NTL 库,以便我可以在我的项目中使用它。
我特别指的是NTL库,但这将是我对系统中任何其他可用外部库的期望方法。
我让 Bazel 按照本答案中的步骤构建我的项目并链接到 NTL。有关详情,请参阅此链接。但是,对于 NTL 库的特定情况,引用的解决方案是不够的。"问题"是NTL默认使用GMP。当我看到由于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_"],
)
然后我创建了"依赖项"目录并将两个文件放入其中。一个是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下的路径可以是特定于平台/机器/用户的。我使用自制的这些路径安装了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