Bazel构建工具入门

1 Bazel简介

1.1 Bazel是什么

Bazel 是 Google 开源的构建 + 测试一体化工具 ,前身是谷歌内部的构建系统 Blaze,2015 年对外开源;名字 Bazel 就是 Blaze 的字母重组词。

定位:类似 Make / CMake / Gradle,但专门为巨型单体仓库 monorepo、多语言、跨平台、可复现构建设计。

1.2 核心特点

声明式构建,Starlark 语言

  • 用 BUILD 文件(语法是 Starlark ,Python 子集)描述目标:cc_binary、cc_library、java_library、py_test 等。
  • 描述的是目标和依赖关系,而不是直接写编译器命令;Bazel 自动推导编译链路,和 Makefile 那种写 shell 命令思路完全不同Bazel。
  • 还有 WORKSPACE 文件,用来声明外部依赖(远程 Git 仓库、Maven 包等)。

内容哈希缓存 + 增量构建 + 远程缓存

  • 只重新编译被改动的目标,并且不是靠文件修改时间,而是文件内容哈希判断是否需要重跑
  • 支持远程缓存、远程执行:多开发者、CI 共享构建产物,大仓库构建速度提升巨大,Google 内部缓存命中率极高Bazel。
  • 自动并行执行互不依赖的构建 / 测试任务。

多语言、跨平台

  • 原生支持 C/C++、Java、Go、Python、Rust、TypeScript、Objective-C
  • 同一套 BUILD 文件,可以编译 Linux/macOS/Windows 服务端、Android、iOS 移动端程序,一套定义多平台输

1.3 适合什么项目

  • 大型单体仓库 monorepo,多语言混编(C++ + Java + Python 共存)
  • 跨平台(同时编译服务器 + 移动端)
  • 大量自动化测试,CI 构建压力大
  • 要求构建结果可复现,团队多开发者协作

2 在Ubuntu中安装Bazel工具

sh 复制代码
curl -LO https://github.com/bazelbuild/bazel/releases/download/7.4.0/bazel-7.4.0-linux-x86_64
chmod +x bazel-7.4.0-linux-x86_64
sudo mv bazel-7.4.0-linux-x86_64 /usr/local/bin/bazel
bazel --version

Ubuntu中下载的很慢,试了下Windows中下载的快一点,下载后复制进来,继续操作。

可以看到bazel的版本是7.4.0了。

3 Bazel构建测试

参考bazel的示例代码:https://github.com/bazelbuild/examples/tree/main/cpp-tutorial/stage1

3.1 测试代码

MODEL.bazel

sh 复制代码
bazel_dep(name = "rules_cc", version = "0.0.17")

main/BUILD

sh 复制代码
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")

cc_binary(
    name = "hello",
    srcs = ["hello.cpp"],
)

main/hello.cpp

c++ 复制代码
#include <ctime>
#include <string>
#include <iostream>

std::string get_greet(const std::string& who) {
  return "Hello " + who;
}

void print_localtime() {
  std::time_t result = std::time(nullptr);
  std::cout << std::asctime(std::localtime(&result));
}

int main(int argc, char** argv) {
  std::string who = "world";
  if (argc > 1) {
    who = argv[1];
  }
  std::cout << get_greet(who) << std::endl;
  print_localtime();
  return 0;
}

项目结构

sh 复制代码
xxpcb@xxpcb-ubuntu20:~/myTest/Bazel/test_demo$ tree
.
└── test1
    ├── main
    │   ├── BUILD
    │   └── hello.cpp
    └── MODULE.bazel

2 directories, 3 files
xxpcb@xxpcb-ubuntu20:~/myTest/Bazel/test_demo$

3.2 开始构建

构建后会从github的bazelbuild下载文件,可能是国内环境受限,报错了。

加了一个国内镜像地址试了也不行。

注意到,在项目中自动生成了一个MODEL.bazel.lock

这个是Bzlmod 去 BCR(Bazel Central Registry)下载 rules_cc,虽然刚才又配置了 ghproxy 的 registry,但ghproxy 有时候访问不稳定,直接超时

3.3 构建失败问题解决

  • 方案A:学习 Bazel 入门,直接关掉 Bzlmod,不用 MODULE.bazel,回到老的 WORKSPACE 模式,不需要联网下载 rules_cc
  • 方案B:继续 Bzlmod + MODULE.bazel,需要配置--module_mirrors,比较复杂,后续再研究

开始修改

3.3.1 代码修改

sh 复制代码
# 删除MODULE.bazel,Bzlmod就不会自动拉取rules_cc了
rm MODULE.bazel

# 创建 WORKSPACE 文件(空文件即可,经典老工作区标记)
touch WORKSPACE

main/BUILD 文件去掉开头load那一行

sh 复制代码
cc_binary(
    name = "hello",
    srcs = ["hello.cpp"],
)

3.3.2 关闭Bzlmod

命令行参数(单次生效)

sh 复制代码
bazel build --noenable_bzlmod //main:hello

写到.bazelrc 永久关闭(推荐,一劳永逸)

sh 复制代码
echo "common --noenable_bzlmod" >> ~/.bazelrc

3.3.3 再次执行

sh 复制代码
bazel build //main:hello
  • // 双斜杠:工作区根目录起点
    • // = 项目根(本例 test1/,里面放 WORKSPACE)
    • //main 就是根目录下的main文件夹
  • : 冒号:分隔 package 路径 和 target 目标名
    • 冒号前面:package(包路径 //main)
    • 冒号后面:target(在 BUILD 文件 内定义的目标名称 hello)

这次执行成功了,注意到生成了多个bazel的目录

3.4 测试可执行程序的运行

3.5 构建产物分析

  • bazel-bin:编译输出的二进制、库、头文件,最终产物在这里
  • bazel-out:构建的核心工作目录,存放编译中间产物(体量最大)
  • bazel-test1:Bazel 的执行根目录(execution root)
  • bazel-testlogs:单元测试的日志目录

3.5.1 bazel目录软链接

生成的bazel目录,实际是软链接,执行~/.cache目录

sh 复制代码
xxpcb@xxpcb-ubuntu20:~/myTest/Bazel/test_demo/test1$ ls -l
total 20
lrwxrwxrwx 1 xxpcb xxpcb  115 Oct 18 16:29 bazel-bin -> /home/xxpcb/.cache/bazel/_bazel_xxpcb/139b038fc59e32075309080b94868442/execroot/__main__/bazel-out/k8-fastbuild/bin
lrwxrwxrwx 1 xxpcb xxpcb   98 Oct 18 16:29 bazel-out -> /home/xxpcb/.cache/bazel/_bazel_xxpcb/139b038fc59e32075309080b94868442/execroot/__main__/bazel-out
lrwxrwxrwx 1 xxpcb xxpcb   88 Oct 18 16:29 bazel-test1 -> /home/xxpcb/.cache/bazel/_bazel_xxpcb/139b038fc59e32075309080b94868442/execroot/__main__
lrwxrwxrwx 1 xxpcb xxpcb  120 Oct 18 16:29 bazel-testlogs -> /home/xxpcb/.cache/bazel/_bazel_xxpcb/139b038fc59e32075309080b94868442/execroot/__main__/bazel-out/k8-fastbuild/testlogs
drwxrwxr-x 2 xxpcb xxpcb 4096 Oct 18 16:28 main
-rw-rw-r-- 1 xxpcb xxpcb    0 Oct 18 16:27 WORKSPACE
xxpcb@xxpcb-ubuntu20:~/myTest/Bazel/test_demo/test1$ 

进入.cache目录看下

sh 复制代码
xxpcb@xxpcb-ubuntu20:~/myTest/Bazel/test_demo/test1/bazel-out$ cd ~/.cache/
xxpcb@xxpcb-ubuntu20:~/.cache$ ls
bazel                                                                       evolution      ibus         mesa_shader_cache     mozilla     thunderbird    update-manager-core
bazelisk                                                                    fontconfig     ibus-table   Microsoft             rhythmbox   tracker        yelp
event-sound-cache.tdb.9fe5b643f31a452cad31d0c22abb2f43.x86_64-pc-linux-gnu  gstreamer-1.0  libgweather  motd.legal-displayed  thumbnails  ubuntu-report
xxpcb@xxpcb-ubuntu20:~/.cache$ cd bazel
xxpcb@xxpcb-ubuntu20:~/.cache/bazel$ ls
_bazel_xxpcb
xxpcb@xxpcb-ubuntu20:~/.cache/bazel$ cd _bazel_xxpcb/
xxpcb@xxpcb-ubuntu20:~/.cache/bazel/_bazel_xxpcb$ ls
139b038fc59e32075309080b94868442  cache  install

再进入bazel/_bazel_xxpcb,有3个子目录

路径:~/.cache/bazel/_bazel_xxpcb/,这一层叫 outputUserRoot,当前用户 xxpcb 全部 Bazel 数据都放这里

  • 139b038fc59e32075309080b94868442:output_base,输出基目录,MD5 哈希
  • cache:全局共享仓库缓存 repository cache
  • install:Bazel 二进制第一次运行时,会把内嵌的 Java 服务 jar、linux-sandbox、辅助工具脚本解压到这里Bazel

3.5.2

MD5哈希
  • 名字是项目工作区路径做 MD5 哈希 生成的一串字符,一个项目对应一个哈希文件夹
  • Bazel Server 进程、编译沙盒、external/外部仓库、编译 action 缓存、编译中间产物
  • 还存 Bazel 服务的 PID、日志、JVM 日志、沙盒执行目录 execroot
  • 命令 bazel clean --expunge 会清空这个目录

如何确认项目对应的哈希值,可以用这个指令

sh 复制代码
xxpcb@xxpcb-ubuntu20:~/myTest/Bazel/test_demo/test1$ bazel info output_base
/home/xxpcb/.cache/bazel/_bazel_xxpcb/139b038fc59e32075309080b94868442
xxpcb@xxpcb-ubuntu20:~/myTest/Bazel/test_demo/test1$ 
cache
  • 跨项目共享!所有 Bazel 工程共用这个缓存
  • 通过 http_archive / Bzlmod 下载的外部压缩包(rules_cc、protobuf 等第三方依赖),按 SHA256 哈希存储
  • 同一个第三方包,A 项目下载过,B 项目再用直接复用,不用重复联网下载
install
  • 不同 Bazel 版本会按哈希分开存放
  • 包含 A-server.jar:Bazel 后台 Server 核心程序
  • 沙盒工具、process-wrapper 等底层执行工具
  • 只要不升级 Bazel 版本,这个目录基本不会变动

3.5.3 构建产物清除

  • bazel clean:清除bazel软链接那些文件
  • bazel clean --expunge:清除cache中对应的哈希目录

4 总结

本篇介绍了Bazel构建工具的基础知识,并在Ubuntu中进行环境配置,使用一个最基础的hello word程序进行编译运行测试。

相关推荐
winfreedoms10 个月前
[特殊字符] 解决 Bazel 在 MediaPipe 项目中报错:“specified in .bazelversion but wasn’t found”
bazel
butteringing2 年前
BuildFarm Worker 简要分析
linux·软件构建·bazel·re api
糖果Autosar2 年前
Writing Bazel rules: library rule, depsets, providers
bazel
糖果Autosar2 年前
Writing Bazel rules: simple binary rule
bazel
m0_740433833 年前
bazel使用中存在的问题
bazel
m0_740433833 年前
bazel远程缓存(Remote Cache)
bazel