BUILD文件是Bazel的声明式构建定义,描述目标、依赖与编译方式;而CMakeLists.txt是过程式脚本,通过命令逐步配置。

什么是Bazel里的BUILD文件,它和CMakeLists.txt有什么区别
BUILD 文件是 Bazel 的构建定义核心,不是配置脚本,而是声明式规则集合。它不执行命令,只描述「哪些源码属于哪个目标」「依赖谁」「怎么编译」。和 CMakeLists.txt 最大不同在于:CMake 是过程式(写一堆 add_executable、target_link_libraries),而 Bazel 要求你显式声明每个目标的类型(cc_binary、cc_library)、可见性(visibility)、头文件包含路径(includes 或 hdrs)——漏一项就可能编译失败或链接找不到符号。
一个最简可用的 cc_binary BUILD 文件长什么样
假设项目结构是:src/main.cc,想编译成可执行文件 hello。在 src/BUILD 里写:
cc_binary(
name = "hello",
srcs = ["main.cc"],
)
注意几点:
-
name是目标名,也是输出二进制名(默认在bazel-bin/src/hello) -
srcs只接受源文件,不自动递归子目录;如果用了#include "utils/math.h",得确保utils/BUILD里有对应cc_library,且当前目标通过deps显式引用 - 没写
deps就无法用 STL 以外的第三方库(比如absl或自定义cc_library),连std::string都可能报错——因为 Bazel 默认不隐式链接libc++,得靠 toolchain 配置或copts控制
常见报错:‘undefined reference to std::…’ 或 ‘no such package’
这两个错误其实指向同一类问题:依赖链断裂。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
-
undefined reference to std::vector<int>::vector():多数是 toolchain 没配好,或者项目根目录缺WORKSPACE文件导致 Bazel 用默认 C++ toolchain(可能不带 libc++)。检查WORKSPACE是否包含load("@bazel_tools//tools/cpp:toolchain_config.bzl", "cc_toolchain_config"),或更简单——加一行cc_binary(copts = ["-std=c++17"]) -
no such package 'third_party/openssl':说明你在deps里写了"@openssl//:ssl",但WORKSPACE没用http_archive声明这个外部 repo。BUILD 文件本身不拉代码,所有外部依赖必须在WORKSPACE中注册 - 头文件找不到?别在
srcs里塞头文件,用hdrs = ["mylib.h"];如果头文件在别的包,得在对应cc_library的visibility里放开(如["//visibility:public"]),否则其他包deps过来也看不到
什么时候必须写 cc_library,而不是全塞进 cc_binary
只要出现以下任一情况,就得拆出 cc_library:
- 多个
cc_binary共享同一组源码(比如cli和test都用parser.cc) - 要单元测试(
cc_test必须deps到被测逻辑的cc_library,不能直接测cc_binary) - 需要控制头文件暴露范围(比如只让内部模块 include
impl/detail.h,对外只 exposeapi.h)→ 用hdrs和srcs分离,再配合visibility - 链接时出现重复符号(multiple definition):通常是因为两个
cc_binary都把同一份.cc放进srcs,导致各自编译一份 → 提炼成cc_library后共用
BUILD 文件真正难的地方不在语法,而在“依赖边界”的判断——哪里该切库、谁该 visible、头文件要不要进 hdrs,这些决定直接影响能否增量编译、是否容易 mock 测试、甚至能不能跨平台复用。写完一个 BUILD,最好跑一遍 bazel query 'deps(//src:hello)' 看依赖图是不是符合预期。

















