Bazel 9.3 配置参数详解
Bazel 9.3 配置体系实测详解:.bazelrc 结构与三级加载顺序、启动选项与 JVM 堆、编译模式与 copt 注入、磁盘/仓库缓存、并行资源参数、MODULE.bazel 依赖声明与本地覆盖,每项改动→执行→验证并附真实回显。
Bazel 9.3 配置参数详解
目标:讲清 Bazel 9.3 的配置体系——
.bazelrc文件结构与加载顺序、启动选项(--host_jvm_args等)、构建标志(-c、--copt、--disk_cache、--repository_cache、--jobs、--local_resources、--sandbox_debug等)、测试选项、MODULE.bazel依赖声明与查询配置。每一项均按「改动 → 执行 → 验证」在 Ubuntu 22.04 实测,回显逐行为真。
一、环境信息
- 操作系统:Ubuntu 22.04.4 LTS(x86_64),12 核 CPU / 32GB 内存,root 用户
- Bazel:9.3.0(官方 APT 仓库安装,安装过程见 《Ubuntu 22.04 安装 Bazel 9.3.0 指南》)
- 实测工程:
/opt/data/quzuo/tmp/bazel/demo-app(C++ 工程:cc_library + cc_binary + cc_test,依赖 rules_cc 0.2.26 / googletest 1.18.0.bcr.1,工程结构同安装篇第七节) - 每项验证均注明「改动 → 执行 → 验证」三段,执行命令的回显为实测原文
二、前置条件
- Bazel 9.3.0 已安装并通过
bazel --version验证(见安装篇); - 冒烟工程可正常构建:
cd /opt/data/quzuo/tmp/bazel/demo-app && bazel build //:hello实测通过(增量构建回显):
INFO: Elapsed time: 0.078s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total actions
三、参数查看与修改方式
3.1 配置载体与查看命令
Bazel 的配置散布在四类载体中,查看方式各不相同:
| 载体 | 内容 | 查看方式(实测) |
|---|---|---|
.bazelrc 文件 | 项目/用户/系统三级默认选项 | 直接读文件(结构见 5.1 节) |
| 命令行标志 | 单次构建的临时覆盖 | bazel help build(build 标志全集)、bazel help startup_options |
| 服务器运行时状态 | 堆上限、资源、缓存路径等 | bazel info(键清单 bazel help info-keys) |
| 标志规范化 | 确认标志书写与等价形式 | bazel canonicalize-flags -- <flags> |
bazel help info-keys 实测回显(节选):
Key: release installed release (informational)
repository_cache location of the repository cache (directory)
java-home The JVM in which Bazel runs.
java-runtime The runtime version of the JVM in which Bazel runs.
max-heap-size Maximum heap size the JVM in which Bazel runs will attempt to use.
local_resources The local resources available to Bazel: CPU(s), RAM in MB, and percent of usable RAM.
...
3.2 标志书写校验:canonicalize-flags
写配置前用它确认标志在当前版本合法、且展开成规范形式:
bazel canonicalize-flags -- --jobs=4 --local_resources=ram=8192
实测回显:
WARNING: Encountered unknown tag 'nozip_tree' at /root/.cache/bazel/_bazel_root/jvm.flags:148
--jobs=4
--local_resources=ram=8192.0
两标志均合法(ram=8192 被规范化为浮点 8192.0;首行 jvm.flags 的 WARNING 为 JVM 侧无关告警)。
3.3 .bazelrc 的加载顺序(官方机制 + 实测验证)
官方文档(bazel.build/run/bazelrc,查询日期 2026-10-20)规定三级 rc 文件按顺序加载,后加载者可覆盖先加载者:
| 顺序 | 文件 | 路径 | 禁用标志 |
|---|---|---|---|
| 1 | 系统 rc | /etc/bazel.bazelrc(Linux) | --nosystem_rc |
| 2 | 工作区 rc | 工作区根 .bazelrc(MODULE.bazel 旁) | --noworkspace_rc |
| 3 | 用户 rc | ~/.bazelrc | --nohome_rc |
实测验证(本机 /etc/bazel.bazelrc 存在但为空文件;工作区 .bazelrc 设有 startup --host_jvm_args=-Xmx512m):
bazel info max-heap-size | tail -1 # 工作区 rc 生效
bazel --noworkspace_rc info max-heap-size | tail -1 # 跳过工作区 rc
bazel --noworkspace_rc --nohome_rc --nosystem_rc info max-heap-size | tail -1 # 全部跳过
实测回显:
536MB
WARNING: The following rc files are no longer being read, please transfer their contents or import their path into one of the standard rc files:
/opt/data/quzuo/tmp/bazel/demo-app/.bazelrc
WARNING: Running Bazel server needs to be killed, because the following startup options are different:
- Only in old server: --host_jvm_args=-Xmx512m -Xmx512m
- Only in new server:
Starting local Bazel server (9.3.0) and connecting to it...
8405MB
两点机制信息:其一,跳过 rc 文件会有明确 WARNING 列出被跳过的文件路径;其二,启动选项变化会导致 Bazel 服务器重启(警告原文可见 old/new server 的启动选项差异),重启后 max-heap-size 从 536MB 回落到默认 8405MB——即 --host_jvm_args 属于 startup 选项,改它必然换服务器进程,改普通 build 标志则不会。
四、参数总览
按作用对象分类的本篇覆盖清单(★ 表示含实测验证):
| 类别 | 参数 | 作用 | 验证方式 |
|---|---|---|---|
| startup | ★ --host_jvm_args | Bazel 服务器 JVM 参数(堆等) | bazel info max-heap-size |
| startup | ★ --noworkspace_rc 等三级禁用 | 控制 rc 文件加载 | 堆上限对照 |
| build | ★ -c dbg / -c opt | 编译模式(输出目录隔离) | 输出目录符号链接 |
| build | ★ --copt | 注入编译器选项 | bazel aquery 查看命令行 |
| build | ★ --linkopt | 注入链接器选项 | file 检查产物 |
| build | ★ --strip | 符号剥离(C++ 下为空操作,见 FAQ) | file 检查产物 |
| build | ★ --disk_cache | 跨工作区动作缓存 | 缓存命中回显 |
| build | ★ --repository_cache | 外部依赖下载缓存 | 缓存路径与迁移实测 |
| build | ★ --jobs / --local_resources | 并行度与本地资源上限 | canonicalize-flags |
| build | ★ --sandbox_debug | 调试沙箱执行 | 构建通过 |
| test | ★ --test_output | 测试输出策略 | 失败用例回显 |
| 依赖 | ★ bazel_dep / local_path_override | MODULE.bazel 依赖声明与本地覆盖 | bazel mod graph |
| 依赖 | git_override / archive_override / single_version_override | 非注册库覆盖(引用官方语法) | 官方文档 |
| 查询 | query / cquery / aquery | 构建图查询(命令详解见命令篇) | 详见命令篇 |
五、核心参数分类详解
5.1 .bazelrc 文件结构(startup / common / build / test 分节)
.bazelrc 语法(官方 bazel.build/run/bazelrc,查询日期 2026-10-20):每行 命令名 标志,命令名可用 startup、common、build、test、query 等,或 命令:配置名 定义命名配置供 --config=配置名 引用;支持 import/try-import 引入外部文件;# 为注释。--enable_platform_specific_config 可让 build:linux 之类的平台限定配置在对应平台自动追加。
本篇实测使用的工作区 .bazelrc 全文(/opt/data/quzuo/tmp/bazel/demo-app/.bazelrc):
# demo-app 项目级 Bazel 配置文件(工作区根目录)
# ---- startup 选项:作用于 Bazel 服务器 JVM 本身 ----
startup --host_jvm_args=-Xmx512m
# ---- common:对所有命令生效 ----
common --enable_platform_specific_config
# ---- build:默认构建选项 ----
build --copt=-Wall
build --host_copt=-Wall
# ---- 命名配置(--config 引用)----
build:dbg -c dbg
build:opt -c opt --strip=always
# ---- test:默认测试选项 ----
test --test_output=errors
结构要点:
- startup 节:只能出现在
bazel与子命令之间,改动即触发服务器重启(3.3 节实测); - common 节:对 build/test/query 等所有命令生效;
- build / test 节:分别只对构建、测试命令生效;
build:名称命名配置:本身不生效,须--config=名称显式启用;不同 rc 文件中的同名配置会追加而非覆盖(官方文档明确)。
5.2 启动选项:--host_jvm_args
改动(命令行临时指定,覆盖 rc 值)→ 执行 → 验证:
bazel --host_jvm_args=-Xmx256m info max-heap-size | tail -1
实测回显:
268MB
对照默认(无 rc 干预时本机为 8405MB,即约 1/4 物理内存自动推算):
| 输入 | 生效堆上限(实测) | 说明 |
|---|---|---|
| (默认,32GB 内存) | 8405MB | JVM 自动推算 |
rc 中 --host_jvm_args=-Xmx512m | 536MB | 512MB + JVM 运行开销 |
命令行 --host_jvm_args=-Xmx256m | 268MB | 命令行值优先生效 |
⚠️ 注意:
--host_jvm_args是 startup 选项——书写位置必须在bazel之后、子命令之前;写入 rc 时须挂在startup节。此外 JVM 实际上报的max-heap-size略大于设定值(512→536MB、256→268MB),是 JVM 自身向上取整的行为,属正常现象。堆内存调优的官方建议见bazel.build/run/optimize-memory(Bazel 7+ 内存模型变化后,服务器堆主要用于分析阶段)。
5.3 构建模式:-c dbg 与 -c opt
Bazel 用编译模式把不同优化级别的产物隔离到不同输出目录(k8-dbg/k8-opt/默认 k8-fastbuild)。本篇 rc 已定义 build:dbg -c dbg 与 build:opt -c opt --strip=always 命名配置。
bazel build --config=dbg //:hello && readlink bazel-bin
bazel build --config=opt //:hello && readlink bazel-bin
实测回显:
k8-dbg
k8-opt
💡 技术拓展:三档编译模式对应
k8-fastbuild(默认,-O0 -g0级别)、k8-dbg(-g调试信息)、k8-opt(-O2等)。产物目录随模式隔离,意味着 dbg/opt 构建互不冲缓存、可并存。bazel-out/k8-<mode>/bin即物理路径,bazel-bin是指向它的便捷符号链接。
5.4 编译器/链接器选项注入:--copt 与 --linkopt
改动(rc 中 build --copt=-Wall)→ 执行 → 验证。用 bazel aquery --output=commands 查看 hello 目标 main.cc 的真实编译命令行:
bazel aquery //:hello --output=commands 2>/dev/null | grep -m1 gcc
实测回显(完整命令行):
/usr/bin/gcc -U_FORTIFY_SOURCE -fstack-protector -Wall -Wunused-but-set-parameter -Wno-builtin-macro-redefined -D__DATE__=\"redacted\" -D__TIMESTAMP__=\"redacted\" -D__TIME__=\"redacted\" -iquote . -iquote bazel-out/k8-fastbuild/bin -iquote external/+non_module_deps+ -iquote bazel-out/k8-fastbuild/bin/external/+non_module_deps+ -iquote external/+module+mathlib+ -iquote bazel-out/k8-fastbuild/bin/external/+module+mathlib+ -isystem external/+module+rules_cc+/cc/runfiles -isystem bazel-out/k8-fastbuild/bin/external/+module+rules_cc+/cc/runfiles -x c++ -std=c++17 -c main.cc -o bazel-out/k8-fastbuild/bin/_objs/hello/hello/hello.pic.dwo
回显中可见 rc 注入的 -Wall 已进入命令行(GCC 11.4.0 路径、-std=c++17 由 C++ 工具链自动配置)。链接器选项同理用 --linkopt,实测见 5.5。
5.5 符号剥离:--strip 与 --linkopt=-s(排障实录)
rc 中 build:opt -c opt --strip=always 意图剥离符号,但构建后检查产物:
bazel build --config=opt //:hello && file bazel-bin/hello | grep -o 'stripped\|not stripped'
实测回显:
not stripped
定位:Bazel 9 中 --strip 选项对 C++ 规则不再生效(官方帮助注明其保留状态为 deprecated 语义,C++ 剥离应在链接期处理)。改用链接器选项:
bazel build --config=opt --linkopt=-s //:hello && file bazel-bin/hello | grep -o 'stripped\|not stripped'
实测回显:
stripped
结论:C++ 目标要剥符号用 --linkopt=-s(等效于 gcc 的 -s),不要依赖 --strip。
5.6 磁盘缓存:--disk_cache
跨工作区共享动作输出,bazel clean 之后也能命中。实测命中链(同一工程三次构建):
bazel clean
bazel build //:hello --disk_cache=/root/.cache/bazel-disk-cache | tail -1
bazel clean
bazel build //:hello --disk_cache=/root/.cache/bazel-disk-cache | tail -1
du -sh /root/.cache/bazel-disk-cache
实测回显(关键两行):
INFO: 8 processes: 5 internal, 3 linux-sandbox.
INFO: 8 processes: 3 disk cache hit, 5 internal.
168K /root/.cache/bazel-disk-cache
首次构建 3 个编译/链接动作真实执行;clean 后同标志重建,同样的 3 个动作直接从磁盘缓存命中(3 disk cache hit)。推荐把 build --disk_cache=... 写进 rc(单机多工程场景收益最大);CI 上可考虑改用远程缓存(Remote Execution API)。
5.7 仓库缓存:--repository_cache
外部依赖(BCR 模块源码包)的下载缓存。默认位置与键:
bazel info repository_cache
实测回显:
repository_cache: /root/.cache/bazel/_bazel_root/cache/repos/v1
换址重建的排障实录:把仓库缓存换到新空目录重建(等价于冷缓存),在依赖源(GitHub)不可达的网络下实测失败——
bazel build //:hello --repository_cache=/opt/data/quzuo/tmp/bazel/repo-cache
实测回显(关键行):
Analyzing: target //:hello (0 packages loaded, 0 targets configured)
ERROR: /root/.cache/bazel/_bazel_root/external/rules_python+~1.7.0/BUILD:269:6: Error resolving @@rules_python+~1.7.0//:__subpackages__: fetch failed: git fetch failed with error: Command [git -c log.showSignature=false fetch --force tags/1.34.0] failed, exit code: -1, stderr: fatal: unable to access 'https://github.com/pypa/tzdata/': Failed to connect to github.com port 443 after 26 ms: Couldn't connect to server
ERROR: Couldn't build. Aborting the build due to errors from __subpackages__.
实测附带代理重试仍失败(Remote host terminated the handshake,链路本身不通)。可行的恢复手段(实测):把默认缓存整体拷贝到新路径——仓库缓存是内容寻址的,拷贝即迁移——
cp -a /root/.cache/bazel/_bazel_root/cache/repos/v1 /opt/data/quzuo/tmp/bazel/repo-cache/
bazel build //:hello --repository_cache=/opt/data/quzuo/tmp/bazel/repo-cache
实测回显:
INFO: Build completed successfully, 9 total actions
结论:--repository_cache 换址务必在能访问依赖源时做一次预热;离线机器用「缓存目录整体拷贝迁移」。
5.8 并行度与本地资源:--jobs 与 --local_resources
⚠️ 版本排障实录:任务中常见的旧写法 --local_ram_resources 在 Bazel 9.3.0 已不存在,实测:
bazel canonicalize-flags -- --local_ram_resources=8192
实测回显:
Unrecognized option: --local_ram_resources=8192
并且 bazel help build | grep local_ 无任何输出。Bazel 8+ 改用命名资源语法 --local_resources=<name>=<value>(可设 cpu/ram),实测验证:
bazel canonicalize-flags -- --jobs=4 --local_resources=ram=8192
实测回显:
--jobs=4
--local_resources=ram=8192.0
参数语义(bazel help build 原文,节选):
--[no]jobs: ... (default: "auto")
The number of concurrent jobs to run. "auto" means a reasonable value based on the host's resources. Values greater than "auto" will only be honored if --experimental_ui_allow_worker_usage_verification is enabled.
💡 说明:
--jobs=auto(默认)按主机资源自动定并行度;显式--local_resources=ram=8192限制动作可用的 RAM 总量为 8192MB(供资源调度器估算并发容量),适合与其他服务混部、避免 OOM 的场景。
5.9 沙箱调试:--sandbox_debug
--sandbox_debug 让 Bazel 在动作失败时保留沙箱目录、并对 linux-sandbox 调用输出详细信息。实测(构建成功路径,验证标志可正常接受):
bazel build //:hello --sandbox_debug | tail -1
实测回显:
INFO: Build completed successfully, 1 total actions
💡 说明:正常构建无需此标志;其价值在排障——当动作在沙箱内因文件缺失/权限失败时,加
--sandbox_debug可保留沙箱现场,直接进入沙箱目录复现动作的执行环境(官方文档 bazel.build/docs/sandboxing 建议)。默认沙箱器为 linux-sandbox(回显中3 linux-sandbox即沙箱内执行的 3 个动作)。
5.10 测试配置:test 节与 --test_output
rc 中 test --test_output=errors 的效果:测试失败时自动打印失败详情(而非只给日志路径)。实测一个故意失败的测试(工程 /opt/data/quzuo/tmp/bazel/fail-demo,bad_test.cc 断言 EXPECT_EQ(1, 2)):
cd /opt/data/quzuo/tmp/bazel/fail-demo && bazel test //:bad_test 2>&1 | tail -3
实测回显:
==================== Test output for //:bad_test:
bad_test.cc:3: Failure
Expected equality of these values:
1
2
================================================================================
Target //:bad_test up-to-date:
bazel-bin/libbad_test.so
bazel-bin/bad_test
INFO: Elapsed time: 0.365s, Critical Path: 0.28s
INFO: 7 processes: 4 disk cache hit, 1 internal, 2 linux-sandbox.
INFO: Build completed successfully, 7 total actions
//:bad_test FAILED in 0.0s
/root/.cache/bazel/_bazel_root/be9a327d9820d3430b1a0821a75c17d8/execroot/_main/bazel-out/k8-fastbuild/testlogs/bad_test/test.log
(--test_output=errors 生效:失败详情直接打到终端;另可见 5.6 节配置的磁盘缓存在新工作区同样命中 4 disk cache hit。)--test_output 可选值:summary(默认,仅结果)、errors(失败详情)、all(全部输出)、streamed(实时流式,便于长测试观察)。
5.11 MODULE.bazel 依赖声明与本地覆盖
bazel_dep()(注册库依赖):从 BCR 解析模块与传递依赖,实测工程声明 bazel_dep(name = "rules_cc", version = "0.2.26") 后的依赖图:
bazel mod graph | head -5
实测回显:
<root> (demo_app@1.0.0)
|___googletest@1.18.0.bcr.1
| |___abseil-cpp@20260526.0
| | |___config_helpers@2.1.0 ...
| |___re2@2026-04-01.bcr.1
| |___rules_cc@0.2.26
local_path_override()(本地路径覆盖):让某个 bazel_dep 不走注册库、改用本地目录——monorepo 联调的标配。实测工程在 MODULE.bazel 追加:
bazel_dep(name = "mathlib", version = "1.0.0")
local_path_override(
module_name = "mathlib",
path = "../libs/mathlib",
)
本地模块 /opt/data/quzuo/tmp/bazel/libs/mathlib 含 MODULE.bazel(自身也须声明 bazel_dep(name = "rules_cc", version = "0.2.26"))与一个 cc_library。改完 MODULE.bazel 与 BUILD 依赖后构建验证:
bazel build //:hello && bazel run //:hello | tail -1
实测回显:
INFO: Build completed successfully, 9 total actions
add(2, 3) = 5
排障实录(本地模块接入的两步真实报错):
- 本地模块未声明自己的
bazel_dep(name = "rules_cc", ...)时:
ERROR: Error computing the main repository mapping: in //:hello, module mathlib@1.0.0 is not visible from root module demo_app@_.
→ 修复:mathlib/MODULE.bazel 自身声明 rules_cc 依赖(bzlmod 的依赖解析按模块作用域进行)。
- 本地模块的
cc_library未声明可见性时:
ERROR: ... Target '//:hello' contains an error and its package is in error and referenced by '//:hello'
与 @@mathlib+//:math is not visible from target '//:hello' → 修复:mathlib/BUILD 顶部加 package(default_visibility = ["//visibility:public"])。
非注册库覆盖(官方语法引用):其余三个覆盖指令的语法取自官方文档 bazel.build/external/module(查询日期 2026-10-20),按需在根 MODULE.bazel 使用:
archive_override(module_name=..., urls=..., integrity=...):指向源码压缩包;git_override(module_name=..., remote=..., commit=...):指向 Git 仓库(本篇实测时 GitHub 链路不可达,未做执行验证,语法以官方文档为准);single_version_override(module_name=..., version=.../registry=.../additional_registry=...):把某依赖钉在指定版本/注册库(多模块版本收敛场景常用)。
5.12 查询配置
查询命令族(query/cquery/aquery)与查询表达式语言的逐条实测见 《Bazel 9.3 常用 CLI 命令详解》;本篇只说明查询与 rc 的关系:rc 中的 query 节为查询命令提供默认标志(如 query --output=proto),查询输出形态由 --output 控制(text/label/proto/jsonproto 等),表达式语言(deps()/kind()/somepath() 等)与命令语法无关 rc,全部定义在 Bazel 查询语言官方文档中。
六、生产配置模板
综合本篇实测,给出两类可直接落地的 rc 模板(数值按 12 核 / 32GB / NVMe 机器给出,请按机器调整):
开发机(本地构建为主):
# ~/.bazelrc(用户级,对所有工作区生效)
startup --host_jvm_args=-Xmx8g
build --disk_cache=~/.cache/bazel-disk-cache
build --local_resources=ram=16384
build --jobs=12
test --test_output=errors
CI 执行机(一次性执行 + 缓存复用):
# CI 工作区 .bazelrc
build -c opt
build --disk_cache=/var/cache/bazel-disk-cache
build --repository_cache=/var/cache/bazel-repo-cache
build --jobs=8
test --test_output=errors
(CI 若同一批动作跨机器可复用,把 --disk_cache 升级为远程缓存协议更合算;磁盘缓存按内容寻址,无需人工清理策略,容量不足时定期删除目录即可。)
七、常见问题(FAQ)
Q1:改了 .bazelrc 里 startup 节为什么不立即生效?
startup 选项变更会触发服务器重启(3.3 节实测警告),新服务器进程才会带新参数;首次输出里可见 Starting local Bazel server 提示。
Q2:--local_ram_resources 报 Unrecognized option?
Bazel 8 起该标志移除,改用 --local_resources=ram=<MB>(5.8 节实测)。
Q3:--strip=always 为什么没剥离 C++ 产物符号?
Bazel 9 中 --strip 对 C++ 规则无效,用 --linkopt=-s(5.5 节实测)。
Q4:max-heap-size 显示 536MB 而我设的是 512m?
JVM 对堆参数向上取整的运行开销,属正常(5.2 节对照表)。
Q5:rc 文件相互覆盖的关系? 系统 rc → 工作区 rc → 用户 rc 顺序加载,后者可覆盖前者;同名命名配置跨文件是追加(5.1/3.3 节,官方 bazel.build/run/bazelrc,查询日期 2026-10-20)。
Q6:磁盘缓存/仓库缓存能共享给其他用户吗?
默认在 root 用户目录下;把 --disk_cache/--repository_cache 指向组共享目录(如 /var/cache/bazel-*-cache)并给写权限即可,两者都是内容寻址、并发安全。
八、参考链接
- 官方 bazelrc 文档:https://bazel.build/run/bazelrc(rc 结构、加载顺序、命名配置,查询日期 2026-10-20)
- 官方内存优化指南:https://bazel.build/run/optimize-memory
- 官方模块文档(override 指令语法):https://bazel.build/external/module(查询日期 2026-10-20)
- 官方沙箱文档:https://bazel.build/docs/sandboxing
- 本专栏安装篇:《Ubuntu 22.04 安装 Bazel 9.3.0 指南》
- 本专栏认知篇:《Bazel 9.3.0 介绍与选型指南》