Bazel 使用总结
摘要
Bazel是一个支持多语言、跨平台的构建工具。Bazel支持任意大小的构建目标,并支持跨多个仓库的构建,是Google主推的一种构建工具。
开源编译的困境:
1、开源成为当前软件开发的主旋律。如何方便地获取依赖,并做到平滑升级很重要。如果构建工具能够很方便地获取源代码。
2、混合多语言编程成为一种选择。每种语言都有自己适用的场景,但是构建多语言的软件系统非常具有挑战性。例如,Python社区很喜欢搭配C/C++,高性能计算扔个C/C++,Python提供编程接口。
3、代码复用。我只想复用第三方的一个头文件,而不是整个系统。拒绝拷贝是优秀程序员的基本素养,如果构建工具能帮我方便地获取到所依赖的组件,剔除不必要的依赖。
4、增量构建。当只修改了一行代码,构建系统能够准确计算需要构建的依赖目标,而不是全构建;否则生命都浪费在编译上了。
5、云构建, 大型软件公司,复用计算资源,可以带来巨大的收益。
Bazel 优势
构建快。支持增量编译。对依赖关系进行了优化,从而支持并发执行。
可构建多种语言。bazel可用来构建Java C++ Android ios等很多语言和框架,并支持mac windows linux等不同平台
可伸缩。可处理任意大小的代码库,可处理多个库,也可以处理单个库
可扩展。使用bazel扩展语言可支持新语言和新平台。
部署使用
方式一:
wget https://copr.fedorainfracloud.org/coprs/vbatts/bazel/repo/epel-7/vbatts-bazel-epel-7.rep --no-check-certificate
mv vbatts-bazel-epel-7.rep /etc/yum.repos.d/
cd /etc/yum.repos.d
mv vbatts-bazel-epel-7.rep vbatts-bazel-epel-7.repo
yum install -y bazel
方式二:
# 下载 demo 用例
git clone https://github.com/abseil/abseil-cpp.git /src/workspace
# 创建一个文件夹,其中包含要在各 build 之间共享的缓存结果
mkdir -p /tmp/build_output/
# 使用 Bazel 容器构建项目,并在主机的输出文件夹中提供构建输出
docker run \
-e USER="$(id -u)" \
-u="$(id -u)" \
-v /src/workspace:/src/workspace \
-v /tmp/build_output:/tmp/build_output \
-w /src/workspace \
l.gcr.io/google/bazel:latest \
--output_user_root=/tmp/build_output \
build //absl/...
# 延申: 使用排错程序构建项目,方法是添加 --config=asan|tsan|msan 构建标志,以便相应地选择 AddressSanitizer (asan)、ThreadSanitizer (tsan) 或 MemorySanitizer (msan)。
docker run \
-e USER="$(id -u)" \
-u="$(id -u)" \
-v /src/workspace:/src/workspace \
-v /tmp/build_output:/tmp/build_output \
-w /src/workspace \
l.gcr.io/google/bazel:latest \
--output_user_root=/tmp/build_output \
build --config={asan | tsan | msan} -- //absl/... -//absl/types:variant_test
用例实践
创建go的运行文件:
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
创建 WORKSPACE 文件:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
urls = [
"https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.19.0/rules_go-0.19.0.tar.gz",
"https://github.com/bazelbuild/rules_go/releases/download/0.19.0/rules_go-0.19.0.tar.gz",
],
sha256 = "9fb16af4d4836c8222142e54c9efa0bb5fc562ffc893ce2abeac3e25daead144",
)
load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")
go_rules_dependencies()
go_register_toolchains()
创建 BUILD.bazel 文件:
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
go_binary(
name = "test",
srcs = ["main.go"],
importpath = "test",
visibility = ["//visibility:private"],
)
编译运行:
bazel run //:test
自动生成
创建t1和t2两个文件夹,写入两个文件:
# 创建 t1 目录
mkdir t1
vi t1/main.go
# 创建 t2 目录
mkdir t2
vi t2/main.go
在项目的根目录的BUILD.bazel中配置加载并配置Gazelle
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix test
gazelle(name = "gazelle")
需要注意的是 # 后面的内容对于Bazel而言是注释,对于Gazelle来说却是一种语法,会被Gazelle运行时所使用。当然Gazelle除了可以通过bazel rule运行,也可以单独在命令行中执行。
根目录下面执行:
# 自动生成
bazel run //:gazelle
# 编译
bazel run t1:t1