跳转到主内容
极星编程网:以代码为星,赴技术山海!

为什么大型c++项目选择Bazel作为构建系统? (对比CMake的优势)

Bazel 通过全量增量构建、远程缓存和沙箱隔离实现更精准的依赖追踪与构建复用,而 CMake 依赖时间戳且缺乏内置分布式缓存;Bazel 显式声明头文件与构建配置,杜绝隐式状态污染,支持确定性跨平台构建,但需手动维护 BUILD 文件且 IDE 集成更复杂。 为什么 Bazel 在大型 C++ 项目里能压住 CMake 的构建时间? 因为 Bazel 默认启用**全量增量构建 + 远程缓存 + 构建动作沙箱隔离**,而 CMake 默认只做“文件时间戳比对”,不跟踪头文件内容变化,也不自带分布式缓存。一个 500 万行的项目,改一个公共头文件
base/status.h
,CMake 可能触发上千个
.o
重编译;Bazel 只会重编译真正依赖该头文件且内容实际被影响的目标。 CMake 的
add_dependencies()
和
target_include_directories(... PRIVATE)
不足以表达“哪些头文件变更会影响哪个目标”,它靠
#include
路径推导依赖,容易漏或过宽 Bazel 的
cc_library(hdrs = ["..."])
显式声明头文件,配合
includes = ["."]
控制可见性,依赖图在解析 BUILD 文件时就固化 Bazel 每次构建前会计算 action 的
digest
(输入源码、编译器路径、flags 全部哈希),哪怕只改了一个空格,也会触发重编译——但这是确定性的,不是“猜” 为什么团队协作时 Bazel 的依赖收敛更可靠? CMake 的
find_package()
或
add_subdirectory()
容易导致隐式全局状态污染:比如 A 模块调用
set(CMAKE_CXX_STANDARD 17)
,可能意外影响 B 模块的编译标准。Bazel 从设计上禁止跨 target 共享构建状态。 每个
cc_library
或
cc_binary
的
copts
、
linkopts
、
defines
必须显式声明,无法被父目录或子目录“继承” 第三方库必须通过
http_archive
+
bind
或
rules_cc
的
cc_import
引入,不能靠系统 PATH 或
find_library("z")
晃过去
//src/storage:db
依赖
//src/utils:status
,就只能访问后者
public_hdrs
中声明的头文件;
private_hdrs
对外部完全不可见 为什么 Bazel 更适合 CI/CD 流水线和多平台交叉编译? 因为 Bazel 把“构建配置”和“构建执行”彻底分离。CMake 的
toolchain file
是运行时动态加载的,而 Bazel 的
--platforms=//platforms:linux_x86_64
是构建图的一部分,所有依赖、工具链、编译器路径都参与依赖分析。 用
config_setting
可以写条件逻辑:
select({"//conditions:linux": ["-m64"], "//conditions:darwin": ["-arch x86_64"]})
,且这些选择在构建图生成阶段就求值完毕 远程执行(RBE)只需加
--remote_executor=grpc://...
,无需改 BUILD 文件;CMake 要接入远程编译得自己写 wrapper、管理 artifact 上传下载 Bazel 的
genrule
和
cc_genrule
天然支持任意脚本生成源码,且输出自动加入构建图——CMake 得靠
add_custom_command(OUTPUT ... COMMAND ...)
,稍不注意就脱离依赖追踪 但 Bazel 真的没有代价吗? 有。最常被低估的是 **BUILD 文件维护成本** 和 **IDE 集成摩擦**。CMakeLists.txt 可以靠
file(GLOB ...)
扫描源码,Bazel 要求所有
srcs
显式列出;VS Code 的 CMake Tools 插件开箱即用,而 Bazel 需要
bzlmod
+
aspect-build/bazel-lib
+ 配置
compile_commands.json
生成规则才能让 clangd 正确跳转。 elasticsearch-9.4.0 win PHP中文网提供Elasticsearch 9.4.0 Windows 版本压缩包下载解压即用,内置 OpenJDK 无需额外配置 Java 环境。该版本重磅推出原生 Prometheus 支持、正式版 Elastic Workflows 以及基于 NVIDIA cuVS 的 GPU 加速向量索引,大幅提升 AI 检索与可观测性能力。建议前往官网下载,快速体验极速搜索与强大的数据分析功能。 下载 立即学习 “ C++免费学习笔记(深入) ”;
# 示例:Bazel 中不能 auto-glob,必须显式写 cc_library( name = "core", srcs = [ "core.cc", "core_impl.cc", # 如果忘了加 new_feature.cc,它根本不会被编译,也不会报错——除非你写了 test 且 test 里没引用它 ], hdrs = ["core.h"], )
还有就是 Windows 下的路径分隔符、MSVC 工具链封装、
cc_import
对 .lib/.dll 的处理,比 CMake 的
add_library(... IMPORTED)
更底层、更易出错。不是不能做,而是得有人懂
cc_toolchain_config.bzl
里怎么配
action_configs
。

相关文章