# bazel-5.3.0-installer-linux-x86_64.sh
chmod +x bazel-version-installer-linux-x86_64.sh
./bazel-version-installer-linux-x86_64.sh
执行输出信息:
Bazel is now installed!
Make sure you have "/usr/local/bin" in your path.
For bash completion, add the following line to your ~/.bashrc:
source /usr/local/lib/bazel/bin/bazel-complete.bash
For fish shell completion, link this file into your
/home/q/.config/fish/completions/ directory:
ln -s /usr/local/lib/bazel/bin/bazel.fish /home/q/.config/fish/completions/bazel.fish
See http://bazel.build/docs/getting-started.html to start a new project!
根据提示,将 source /usr/local/lib/bazel/bin/bazel-complete.bash
添加到 ~/.bashrc 中:
echo 'source /usr/local/lib/bazel/bin/bazel-complete.bash' >> ~/.bashrc
source ~/.bashrc
测试安装:
bazel --version # bazel 5.3.0
接下来以官方给出的 demo进行学习,这个项目有 C++、java、android、java-maven等示例,进入 C++ 项目示例即可。
.
├── README.md
├── stage1
│ ├── main
│ │ ├── BUILD
│ │ └── hello-world.cc
│ ├── README.md
│ └── WORKSPACE
├── stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-greet.cc
│ │ ├── hello-greet.h
│ │ └── hello-world.cc
│ ├── README.md
│ └── WORKSPACE
└── stage3
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
├── main
│ ├── BUILD
│ ├── hello-greet.cc
│ ├── hello-greet.h
│ └── hello-world.cc
├── README.md
└── WORKSPACE
stage1、stage2、stage3 是三个独立的示例工程项目(三个工程之间没有直接关系):
工作区是保存项目源文件和 Bazel 构建输出的目录。bazel相关的:
BUILD 文件包含了一系列不同类型的指令,Bazel 工具执行这些指令,来构建和编译目标(target: 想生成的东西,如源代码生成的二进制可执行文件、.o中间文件、lib 库文件等等):
BUILD 文件中,最重要命令的就是 构建规则(build rule),它告诉 Bazel 如何去创建和生成我们的目标。比如 cpp-tutorial/stage1/main 目录下的 BUILD 文件,内容如下:
load("@rules_cc//cc:defs.bzl", "cc_binary")
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
上面规则中, hello-world 就是目标target, hello-world.cc 就是依赖文件,意思就是说,使用 hello-world.cc 文件,编译生成一个想要的名为 hello-world 的可执行文件。
cc_binary 生成可执行文件
cc_library生成lib文件
更多规则参考1
更多规则参考2
.
├── main
│ ├── BUILD
│ └── hello-world.cc
├── README.md
└── WORKSPACE
对stage-1进行编译: bazel build //main:hello-world
//main
: 是相对路径,相对于工作区间 workspace 的根目录的路径
hello-world
是目标target
Bazel工具使用 main 目录下 BUILD 这个文件指定的编译规则,来编译生成目标. 编译过程,打印下面信息:
Starting local Bazel server and connecting to it...
INFO: Analyzed target //main:hello-world (37 packages loaded, 163 targets configured).
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 6.254s, Critical Path: 0.47s
INFO: 6 processes: 4 internal, 2 linux-sandbox.
INFO: Build completed successfully, 6 total actions
这时,项目空间的根目录下,生成目录 bazel-bin (生成了一些快捷方式,文件原位置在缓存中),这个目录中,包含有刚才编译生成的目标:
.
├── bazel-bin -> /home/q/.cache/bazel/_bazel_q/e090bbc49e2071052269526408283032/execroot/__main__/bazel-out/k8-fastbuild/bin
├── bazel-out -> /home/q/.cache/bazel/_bazel_q/e090bbc49e2071052269526408283032/execroot/__main__/bazel-out
├── bazel-stage1 -> /home/q/.cache/bazel/_bazel_q/e090bbc49e2071052269526408283032/execroot/__main__
├── bazel-testlogs -> /home/q/.cache/bazel/_bazel_q/e090bbc49e2071052269526408283032/execroot/__main__/bazel-out/k8-fastbuild/testlogs
├── main
│ ├── BUILD
│ └── hello-world.cc
├── README.md
└── WORKSPACE
执行编译生成的可执行文件 bazel-bin/main/hello-world
Hello world
Wed Oct 12 13:55:46 2022
查看目标是依赖哪些文件生成,即可视化项目的依赖关系,可以通过在工作区根目录运行如下命令,来生成依赖关系图的文本表示:
bazel query --notool_deps --noimplicit_deps "deps(//main:hello-world)" --output graph
执行结果如下:
digraph mygraph {
node [shape=box];
"//main:hello-world"
"//main:hello-world" -> "//main:hello-world.cc"
"//main:hello-world.cc"
}
上面的命令告诉 Bazel 查找目标 //main:hello-world 的所有依赖项(不包括主机和隐式依赖项)并将输出格式化为图形。然后,将文本粘贴到 GraphViz 中进行可视化。
此外,还可以通过安装 GraphViz 和 xdot Dot Viewer 在本地查看图形:
sudo apt update && sudo apt install graphviz xdot
然后,您可以通过将上面的文本输出直接传送到 xdot 来生成和查看图形:
xdot <(bazel query --notool_deps --noimplicit_deps "deps(//main:hello-world)" --output graph
在stage1示例中,只有一个 .cc 源文件,但实际项目开发中,一般会有多个 .cc 源文件。如何编译多个 .cc 源文件这种情况。先进入示例 stage2 工程目录下.
.
├── main
│ ├── BUILD
│ ├── hello-greet.cc
│ ├── hello-greet.h
│ └── hello-world.cc
├── README.md
└── WORKSPACE
查看该项目下 main 文件夹下的 BUILD 文件,内容如下:
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
],
)
执行命令来编译 stage2 这个工程:
bazel build //main:hello-world
编译完成以后,尝试执行一下生成的二进制文件:
bazel-bin/main/hello-world
打印结果如下:
Hello world
Wed Oct 12 14:13:25 2022
如果这时候,去修改 hello-greet.cc 这个源文件,那么,bazel 只会重新编译 ``hello-greet.cc` 这个文件,其它文件不会被重新编译。
查看一下依赖关系图:
xdot <(bazel query --nohost_deps --noimplicit_deps 'deps(//main:hello-world)' --output graph)
可以将项目拆分为多个包,看一下cpp-tutorial/stage3目录的内容.
.
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
├── main
│ ├── BUILD
│ ├── hello-greet.cc
│ ├── hello-greet.h
│ └── hello-world.cc
├── README.md
└── WORKSPACE
现在有两个子目录,每个子目录都包含一个 BUILD 文件。 因此,对于 Bazel,工作区现在包含两个包: lib 和 main
lib/BUILD 文件:
load("@rules_cc//cc:defs.bzl", "cc_library")
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["//main:__pkg__"], #对 main 包可见
)
main/BUILD 文件:
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
"//lib:hello-time",
],
)
未编译也可(通过 BUILD) 查看依赖关系:
xdot <(bazel query --nohost_deps --noimplicit_deps 'deps(//main:hello-world)' \
> --output graph)
编译并执行
bazel build //main:hello-world
bazel-bin/main/hello-world
输出:
Hello world
Wed Oct 12 14:35:26 2022
常见 C++ 构建用例
cc_library(
name = "build-all-the-files",
srcs = glob(["*.cc"]),
hdrs = glob(["*.h"]),
)
cc_library(
name = "mylib",
srcs = ["mylib.so"],
hdrs = ["mylib.h"],
)
规则查询
函数查询
概览
bazel 命令行参考文档
使用 Bazel 构建程序