0%

[笔记] Envoy bazel 学习 & 踩坑

近一年有开始折腾 Envoy 了,在 bazel 这块踩了一些坑,总结记录下的,主要是个人的体感,不一定准确,欢迎批评指正。

bazel 是个啥

编译构建工具,跟常用的 Makefile 是类似的。

只是,bazel 更复杂,上手门槛更高,以我的个人的体验来看,主要是为了提升表达能力,可编程能力更强。

Makefile 通常是用于简单的描述,偶尔会搞个函数啥的;但是在 bazel 里,会看到大面积的自定义函数。

为啥 Envoy 需要 bazel

Envoy 是个 C++ 项目,C/C++ 这种比较老的语言,没有内置依赖包管理器这种先进特性(相比较而言,Go 语言在这块就先进了许多)。

我的理解,对于 Envoy 来说,bazel 一个主要的作用就是,补齐了依赖包管理。如果仅仅是编译,Makefile 之类的简单工具,应该也够用了。

几个概念

有几个常用的基本概念,先了解一下的

WORKSPACE

在项目的根目录,会有一个 WORKSPACE 文件,用于描述整个项目的,最主要是描述了依赖库,比较类似于 Go 语言中的 go.modgo.sum

比如 Envoy 的 WORKSPACE 文件中,有这样的描述:

1
2
load("//bazel:repositories.bzl", "envoy_dependencies")
envoy_dependencies()

其中,具体依赖库的详细信息,在 bazel/repository_locations.bzl 文件里。
比如下面这个示例:

1
2
3
4
5
6
7
8
boringssl = dict(
project_name = "BoringSSL",
project_url = "https://github.com/google/boringssl",
version = "098695591f3a2665fccef83a3732ecfc99acdcdd",
sha256 = "e141448cf6f686b6e9695f6b6459293fd602c8d51efe118a83106752cf7e1280",
strip_prefix = "boringssl-{version}",
urls = ["https://github.com/google/boringssl/archive/{version}.tar.gz"],
),

描述的是依赖库 boringssl,是不是很像 go.modgo.sum

另外,在这里还可以频繁看到 @envoy @envoy_api 这种,这里也表示的一个依赖库的作用域。

BUILD

BUILD 文件会有很多个,用于描述一个目标的编译过程,类似于 Makefile 中描述一个目标的构建过程。

比如,这样子的:

1
2
3
4
5
6
7
8
9
10
envoy_cc_library(
name = "lua_filter_lib",
srcs = ["lua_filter.cc"],
hdrs = ["lua_filter.h"],
deps = [
":wrappers_lib",
"//envoy/http:codes_interface",
"@envoy_api//envoy/extensions/filters/http/lua/v3:pkg_cc_proto",
],
)

.bazelrc

这也是在项目根目录下的,用于描述 bazel 的默认配置。

比如,这个:

1
build:linux --copt=-Wno-deprecated-declarations

可以指定一些编译参数之类的。

执行

有了上面这些描述信息之后,最终要执行编译构建的命令就简单许多了

比如:

1
bazel build envoy

这里的构建目标 envoy,来自项目根目录下的 BUILD 文件。

也可以是这样子的:

1
bazel build //source/exe:envoy

此时的构建目标 //source/exe:envoy,来自项目根目录下的 source/exe/BUILD 文件了。

踩过的坑

除了上面这些一手体感,还有一些坑,也记录下的

变更编译器版本

有一次,想换个高版本的 gcc,但是修改了 PATH 后重新构建,始终不生效。

原来是,bazel 是增量编译的,所以会使用上一次编译时使用编译器,以保证整个项目是使用的同一个编译器。

所以,如果想更换编译器,需要清空下缓存:

1
bazel clean --expunge

split DWARF

较新版的 Envoy,启用了 -gsplit-dwarf 这个特性,也就是将调试符号放到独立的 .dwo 文件里了,以减少生成的二进制文件大小。

不过呢,这个特性还比较新,可能会有一些坑,至少在我的环境下(gdb 11,这个版本也不低了),就有 .dwo 读取错误。
比如这样子的:

1
DW_FORM_strp pointing outside of .debug_str section

所以,干脆关掉这个特性,就一切正常了(主要是 bt full 这类查看局部变量的功能)。

具体操作是,注释掉 .bazelrc 中的这一行:

1
# build:linux --features=per_object_debug_info

最后

记录下,我这边可以完整工作的环境:

  1. g++ 11
  2. gdb 11

在这个环境下,gdb 是可以完整工作的,局部变量都可以看。

之前在一个比较老的版本上,工作是不太顺利的。