Bazel 构建系统

FreeGuideOnline 最新 2026-07-11

bash brew install bazelisk


**Linux**
```bash
# 下载 Bazelisk 可执行文件
wget https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64
chmod +x bazelisk-linux-amd64
sudo mv bazelisk-linux-amd64 /usr/local/bin/bazel

Windows (Chocolatey)

choco install bazelisk

安装后,执行 bazel version 验证是否成功。

核心概念速览

Bazel 的世界由几个关键抽象构成,理解它们才能阅读和编写构建文件。

工作空间(Workspace)

工作空间是包含 WORKSPACE(或 WORKSPACE.bazel)文件的目录,是整个项目的根。该文件用于引入外部依赖。

包(Package)

包是包含 BUILDBUILD.bazel 文件的目录。一个工作空间可以包含多个包,每个包定义了一组构建目标。

目标(Target)

目标是构建产物的最小单元,例如一个 Java 库、一个 C++ 可执行文件或一个容器镜像。目标由 标签(Label) 唯一标识,格式为 //package:target,若省略 target 部分则默认为 //package:package_name

规则(Rule)

规则定义如何从输入生成输出。Bazel 内置大量规则,如 java_librarycc_binarygenrule 等。开发者也可自定义规则。

动手:第一个 Bazel 项目

我们创建一个简单的 Java 应用来感受构建流程。创建以下目录结构:

my-project/
├── WORKSPACE
├── BUILD
└── src/
    └── main/
        └── java/
            └── com/
                └── example/
                    ├── BUILD
                    └── Greeting.java

设置工作空间

WORKSPACE 文件可以为空,它标记了工作空间根目录。外部依赖后续会在这里声明。

编写 Java 源码

src/main/java/com/example/Greeting.java

package com.example;

public class Greeting {
  public static void sayHi() {
    System.out.println("Hello from Bazel!");
  }
}

定义构建目标

src/main/java/com/example/BUILD 文件中声明一个 Java 库:

java_library(
    name = "greeting",
    srcs = ["Greeting.java"],
    visibility = ["//:__pkg__"],  # 对本工作空间的包可见
)

在项目根目录的 BUILD 文件中声明一个可执行目标,使其依赖上面的库:

java_binary(
    name = "hello",
    main_class = "com.example.Greeting",
    runtime_deps = ["//src/main/java/com/example:greeting"],
)

构建与运行

在项目根目录执行:

bazel build //:hello

首次构建会下载相关规则和依赖,之后再次构建速度极快。运行输出:

bazel run //:hello
# 输出:Hello from Bazel!

若要生成可执行 JAR 包,可以执行:

bazel build //:hello_deploy.jar
java -jar bazel-bin/hello_deploy.jar

处理外部依赖

Bazel 建议将第三方依赖显式声明,实现可复现构建。以 Java 的 Guava 库为例。

编辑 WORKSPACE 文件,添加 Maven 仓库规则(需先加载 rules_jvm_external):

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

RULES_JVM_EXTERNAL_TAG = "4.5"
RULES_JVM_EXTERNAL_SHA ="..."

http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
    sha256 = RULES_JVM_EXTERNAL_SHA,
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)

load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
rules_jvm_external_deps()

load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
rules_jvm_external_setup()

load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
    artifacts = [
        "com.google.guava:guava:31.1-jre",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

注意:SHA 值请从 rules_jvm_external 的发布页获取。添加后,在 BUILD 文件中引用 Guava:

java_library(
    name = "greeting",
    srcs = ["Greeting.java"],
    deps = ["@maven//:com_google_guava_guava"],
    visibility = ["//:__pkg__"],
)

重新运行构建,Bazel 会自动下载并缓存依赖。

多语言构建示例:C++

Bazel 对 C++ 的支持同样简洁。假设有一个 hello.cpp 文件,位于 cpp/ 包内:

cpp/hello.cpp

#include <iostream>
int main() {
    std::cout << "Hello from C++!" << std::endl;
    return 0;
}

cpp/BUILD

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

运行:

bazel run //cpp:hello

如果依赖第三方 C++ 库,可以使用 http_archiveWORKSPACE 中引入,并用 cc_library 引用。

构建缓存与远程执行(进阶概念)

Bazel 的极速构建得益于其细粒度的缓存机制。本地缓存默认开启,所有构建输出会存储在输出基目录下。

远程缓存(Remote Cache):允许多个开发者或 CI 机器共享构建输出,大幅减少重复编译时间。只需在 .bazelrc 文件中配置:

build --remote_cache=grpc://cache.example.com:9090