Bazel 教程
Bazel 语法详解
Bazel 的核心是 WORKSPACE
和 BUILD
文件。它们使用 Starlark 语言(一种 Python 方言)编写。以下是 Bazel 语法的详细说明。
1. WORKSPACE
文件
WORKSPACE
文件用于定义工作空间的根目录,并声明外部依赖(如第三方库或工具链)。它是一个全局配置文件。
示例:
workspace(name = "my_project")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# 下载一个外部依赖(例如 rules_go)
http_archive(
name = "io_bazel_rules_go",
sha256 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
urls = ["https://github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip"],
)
# 加载外部依赖
load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")
go_rules_dependencies()
go_register_toolchains()
关键点:
workspace(name = "my_project")
:定义工作空间的名称,必须是唯一的。load()
:用于加载外部规则或工具。http_archive()
:用于下载外部依赖。
2. BUILD
文件
BUILD
文件用于定义构建目标(如二进制文件、库、测试等)。每个目录可以有一个或多个 BUILD
文件。
示例:
# 定义一个 C++ 二进制文件
cc_binary(
name = "hello_world",
srcs = ["main.cc"],
deps = [":hello_lib"],
)
# 定义一个 C++ 库
cc_library(
name = "hello_lib",
srcs = ["hello.cc"],
hdrs = ["hello.h"],
visibility = ["//visibility:public"],
)
# 定义一个 C++ 测试
cc_test(
name = "hello_test",
srcs = ["test.cc"],
deps = [":hello_lib"],
)
关键点:
- 目标类型:
cc_binary
:生成可执行文件。cc_library
:生成库文件(静态库或动态库)。cc_test
:生成测试可执行文件。
- 属性:
name
:目标的名称,必须是唯一的。srcs
:源文件列表(如.cc
文件)。hdrs
:头文件列表(如.h
文件)。deps
:依赖的其他目标(如库)。visibility
:控制目标的可见性(如//visibility:public
表示对所有目标可见)。
3. 常用规则(Rules)
Bazel 支持多种编程语言,每种语言都有对应的规则。以下是一些常用规则:
C++ 规则
cc_binary
:生成可执行文件。cc_library
:生成库文件。cc_test
:生成测试可执行文件。
Java 规则
java_binary
:生成可执行 JAR 文件。java_library
:生成 Java 库。java_test
:生成 Java 测试。
Python 规则
py_binary
:生成可执行 Python 脚本。py_library
:生成 Python 库。py_test
:生成 Python 测试。
Go 规则
go_binary
:生成可执行 Go 程序。go_library
:生成 Go 库。go_test
:生成 Go 测试。
4. 依赖管理
Bazel 的依赖分为两种:
- 内部依赖:同一工作空间内的目标。
- 外部依赖:通过
WORKSPACE
文件引入的第三方库。
内部依赖
在 BUILD
文件中,通过 deps
属性引用其他目标:
cc_binary(
name = "my_program",
srcs = ["main.cc"],
deps = ["//path/to:my_library"],
)
外部依赖
在 WORKSPACE
文件中,通过 http_archive
或 git_repository
引入:
http_archive(
name = "com_google_googletest",
urls = ["https://github.com/google/googletest/archive/v1.11.0.zip"],
strip_prefix = "googletest-1.11.0",
)
然后在 BUILD
文件中引用:
cc_test(
name = "my_test",
srcs = ["test.cc"],
deps = ["@com_google_googletest//:gtest"],
)
5. 可见性(Visibility)
Bazel 通过 visibility
属性控制目标的可见性。默认情况下,目标仅对同一 BUILD
文件中的其他目标可见。
示例:
cc_library(
name = "my_lib",
srcs = ["lib.cc"],
hdrs = ["lib.h"],
visibility = ["//visibility:public"], # 对所有目标可见
)
//visibility:public
:对所有目标可见。//visibility:private
:仅对同一BUILD
文件中的目标可见。//path/to:__pkg__
:仅对指定路径下的目标可见。
6. 标签(Labels)
Bazel 使用标签(Labels)来唯一标识目标。标签的格式为:
//path/to:target_name
//
:表示工作空间根目录。path/to
:目标所在的目录路径。target_name
:目标的名称。
示例:
//:hello_world
:根目录下的hello_world
目标。//src:main
:src
目录下的main
目标。
7. 构建和运行命令
- 构建目标:
bazel build //path/to:target_name
- 运行目标:
bazel run //path/to:target_name
- 测试目标:
bazel test //path/to:target_name
8. Demo:C++ 项目
以下是一个完整的 C++ 项目示例:
项目结构
my_project/
├── WORKSPACE
├── BUILD
├── main.cc
├── hello.cc
├── hello.h
└── test.cc
WORKSPACE
workspace(name = "my_project")
BUILD
cc_binary(
name = "hello_world",
srcs = ["main.cc"],
deps = [":hello_lib"],
)
cc_library(
name = "hello_lib",
srcs = ["hello.cc"],
hdrs = ["hello.h"],
visibility = ["//visibility:public"],
)
cc_test(
name = "hello_test",
srcs = ["test.cc"],
deps = [":hello_lib"],
)
main.cc
#include "hello.h"
int main() {
say_hello();
return 0;
}
hello.h
#ifndef HELLO_H
#define HELLO_H
void say_hello();
#endif
hello.cc
#include <iostream>
#include "hello.h"
void say_hello() {
std::cout << "Hello, Bazel!" << std::endl;
}
test.cc
#include "hello.h"
#include <cassert>
void test_say_hello() {
// Test
assert(true);
}
int main() {
test_say_hello();
return 0;
}
构建和运行
# 构建
bazel build //:hello_world
# 运行
bazel run //:hello_world
# 测试
bazel test //:hello_test