
MongoDB 仓库 Bazel 构建开发工作流完全指南从 BUILD.bazel 编写到 clang-tidy 集成【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo本文是 MongoDB 服务器源码仓库中 Bazel 构建系统的开发者实战指南聚焦 Server 开发者日常修改 Bazel 构建定义BUILD.bazel的完整工作流如何新建构建目标、静态声明头文件与源文件、声明库依赖、以及通过 Bazel 运行 clang-tidy 静态分析。读完本文你将掌握 MongoDB 仓库特有的mongo_cc_binary/mongo_cc_library/idl_generator宏的用法与依赖解析规则并能独立解决头文件该加到哪里这一高频构建问题。1. 概览Bazel 在 MongoDB 仓库中的角色MongoDB 服务器仓库当前工作目录根即仓库根使用 Bazel 作为构建系统构建定义以BUILD.bazel文件的形式散落在源码目录中。与src/mongo目录约 5700 个.cpp与 3600 个.h文件一一对应的BUILD.bazel文件共同构成了整个服务器的构建图。Bazel 的构建目标定义在源码所在目录的BUILD.bazel文件中。DevProd Build 团队为 MongoDB 定制了专用宏封装在 bazel/mongo_src_rules.bzl 中包括mongo_cc_binary可执行程序目标cc_binary的封装见 mongo_src_rules.bzl#L799mongo_cc_library库目标cc_library的封装见 mongo_src_rules.bzl#L303idl_generatorIDLInterface Description Language代码生成器目标见 mongo_src_rules.bzl#L1224。这些宏是普通 Bazel 原生规则的上层封装会自动注入 MongoDB 特有的全局依赖如libunwind并处理 auto-header 等仓库特有的构建逻辑。2. 创建新的 BUILD.bazel 文件构建目标定义在源码所在目录下。例如要编译src/mongo/hello_world.cpp就需要在src/mongo/目录下创建src/mongo/BUILD.bazel内容如下mongo_cc_binary( name hello_world, srcs [ hello_world.cpp ], }2.1 获取 Bazel仓库不要求手工安装 Bazel而是提供了安装脚本。运行python buildscripts/install_bazel.py该脚本buildscripts/install_bazel.py会下载 bazelisk当前固定为 v1.26.0并放置到工具链目录同时创建bazel - bazelisk符号链接create_bazel_to_bazelisk_symlink使后续bazel命令可直接使用。在ppc64le、s390x等 bazelisk 二进制不支持的平台上脚本会回退到仓库内的 bazel/bazelisk.py。2.2 构建与运行目标构建该目标bazel build //src/mongo:hello_world运行该目标bazel run //src/mongo:hello_world2.3 目标标签Label的构成规则完整的 Bazel 目标标签由BUILD.bazel所在目录与该目录内的目标名组合而成//{BUILD.bazel dir}:{targetname}即//src/mongo:hello_world 包路径src/mongo 目标名hello_world。这个标签语法在bazel build/bazel run命令、以及下文deps声明中通用。3. 添加新的头文件 / 源文件Bazel 尽可能使用静态分析来提升执行与查询速度。因此MongoDB 仓库禁止在构建目标中动态声明文件例如使用glob、通配符等。每新增一个头文件或源文件都必须手工将其引用添加进对应构建目标mongo_cc_binary( name hello_world, srcs [ hello_world.cpp, new_source.cpp # 新增源文件时加入 ], hdrs [ new_header.h # 新增头文件时加入 ], }3.1 源码层面的印证静态声明如何被执行从实现看mongo_cc_library会处理srcs、hdrs、private_hdrs、textual_hdrs等静态声明的文件列表mongo_src_rules.bzl#L303-L336。其中textual_hdrs用于无需单独编译、直接文本包含的.cpp文件private_hdrs是该库私有、不对外导出的头文件。此外仓库在 bazel/auto_header/ 中实现了 auto-header 机制见 auto_header.bzl对于.c/.cc/.cpp/.h/.hpp/.hh/.hxx等扩展名mongo_cc_library默认auto_header True会基于已声明的源文件自动推导出与每个源文件同名的头文件并将它们并入srcsmongo_src_rules.bzl#L396-L406。也就是说常规的foo.cpp foo.h配对通常可依赖自动推导但新增一个独立的、不与任何源文件同名的头文件时必须显式写入hdrs。4. 添加新的库创建新库与创建新二进制的步骤类似也是在对应目录的BUILD.bazel中新增一条mongo_cc_library定义mongo_cc_library( name new_library, srcs [ new_library_source_file.cpp ] }mongo_cc_library是对原生cc_library的封装支持的常用参数包括默认值见 mongo_src_rules.bzl#L303-L336参数默认值作用srcs[]参与编译的源文件hdrs[]该库对外公开的头文件textual_hdrs[]文本式包含的头文件/源文件不单独编译private_hdrs[]库私有头文件deps[]依赖的 Bazel 目标cc_deps[]同deps但不会作为共享库依赖被加入copts/cxxopts[]额外编译选项linkopts[]链接选项会传递给依赖该库的目标defines[]宏定义编译本目标及其依赖方时均生效local_defines[]宏定义仅编译本目标源码时生效includes[]导出给依赖方的 include 目录自动加包路径前缀skip_global_deps[]跳过全局注入依赖可选值如libunwind、allocatortestonlyFalse仅用于测试auto_headerTrue是否启用头文件自动推导值得注意的仓库特性mongo_cc_library默认会把libunwind加入deps除非在skip_global_deps中显式排除见 mongo_src_rules.bzl#L379-L380。linkstatic参数当前不受支持——MongoDB 的构建必须整体静态链接或整体动态链接由//config/bazel:linkstatic统一配置。4.1 IDL 生成目标对于包含.idl文件的模块使用idl_generator生成解析器代码idl_generator( name some_command_gen, srcs [some_command.idl], )从源码看idl_generator会自动为每个目标补充//src/mongo:idl_headers这一文件组其中包含bsonobj.h、idls_parser.h、server_parameter.h等 IDL 生成代码必需的公共头文件见 src/mongo/BUILD.bazel#L311 起的idl_headersfilegroup并且默认注入//src/mongo/db/query:explain_verbosity_gen作为隐式依赖除非idl_self_dep True详见 mongo_src_rules.bzl#L1224-L1237。5. 声明依赖如果某个库或二进制依赖另一个库必须在目标的deps段中显式声明。引用库的语法与bazel build/bazel run命令中的标签语法完全一致mongo_cc_library( name new_library, # ... } mongo_cc_binary( name hello_world, srcs [ hello_world.cpp, ], deps [ :new_library, # 引用同目录 BUILD.bazel 中声明的库 # //src/mongo:new_library # 绝对路径写法 # sub_directory:new_library # 子目录的相对路径写法 ], }三种依赖引用方式说明:new_library同包内引用冒号前的包路径留空表示当前BUILD.bazel所在目录//src/mongo:new_library从仓库根目录开始的绝对标签sub_directory:new_library相对于当前包的子目录引用。Bazel 会依据完整的依赖图进行增量构建与缓存。从实现看mongo_cc_binary底层统一走_mongo_cc_binary_and_test逻辑mongo_src_rules.bzl#L851并自动打上mongo_binarytag便于后续按 tag 过滤查询。6. 通过 Bazel 运行 clang-tidy注意该特性仍处于开发中相关跟踪单为 SERVER-80396但仓库已提供了可用的配置与命令。6.1 运行方式分析全部代码bazel build --configclang-tidy src/...分析单个目标例如environment_buffer。注意目标名带_with_debug后缀bazel build --configclang-tidy src/mongo/db/commands:environment_buffer_with_debug6.2 配置在仓库中的落点clang-tidy的构建配置定义在根目录 .bazelrc 中.bazelrc#L602-L610核心行为包括--remote_download_outputsall远程执行时下载全部输出含 clang-tidy 报告--build_tag_filtersnot_third_party,-mongo-tidy-tests,-mongo-tidy-tests_debug跳过第三方代码与 tidy 自测目标只分析 MongoDB 自身代码--//bazel/config:compiler_typeclang强制使用 clang 编译器clang-tidy 依赖 clang 工具链--keep_going单个目标失败不中断其余分析--aspects bazel_clang_tidy//clang_tidy:clang_tidy.bzl%clang_tidy_aspect以 aspect 方式挂接到构建图上运行 clang-tidy--output_groupsreport产出 tidy 报告作为输出--jobs300并行分析任务数。clang-tidy 的配置文件由根目录 BUILD.bazel 中的clang_tidy_config/clang_tidy_config_strict目标生成通过//buildscripts:clang_tidy_config_gen.py生成器并通过clang_tidy_merge_tool//bazel:merge_tidy_configs合并MongoDB 自研的 tidy 检查插件mongo_tidy_checks也通过clang_tidy_plugin_deps挂载见 .bazelrc#L161-L167。6.3 自测 clang-tidy 是否真的能发现问题如果想验证 clang-tidy 确实在工作可以向某个.cpp文件注入以下代码触发bugprone-incorrect-roundings警告const double f 1.0; const int foo (int)(f 0.5);该模式是浮点数 0.5 再截断的经典错误舍入写法clang-tidy 的bugprone-incorrect-roundings检查会对此报警。7. FAQ头文件应该加到哪里7.1 头文件在多处被引用如何定位应在哪些 BUILD.bazel 中声明遵循以下循环定位流程直接用 Bazel 构建以加速定位bazel build //src/...构建会在第一个缺失头文件依赖处失败。在 bazel 构建文件中搜索该头文件所属的库目前仍存在头文件放错位置的情况需要结合经验判断。若该头文件已存在于某个库中就把该库加入deps。例如scoped_timer.h属于scope_timer库就在deps中加入//src/mongo/db/exec:scoped_timer——这样做还能自动带上scoped_timer.h的传递依赖对应库定义位于 src/mongo/db/exec/BUILD.bazel#L64 附近的scoped_timer目标。如果头文件不属于任何现有库则直接把它加入编译失败的那个库的hdrs字段再次直接构建bazel build //src/...若出现依赖环则撤销第 2 步加入的依赖改为把头文件作为直接依赖放入hdrs字段然后回到第 1 步重新循环。7.2 头文件被几十处甚至更多位置引用正确归位需要大规模重构、阻塞关键工作时怎么办如果已经投入大量精力确认将该头文件放到正确位置通常是与其关联的.cpp文件放在一起并让所有依赖方把该库加为dep需要一次大规模重构可以创建 SERVER ticket说明问题、解决方案与解决所需的工作量打开src/mongo/BUILD.bazel把头文件加入core_headers文件组并在 TODO 注释中引用该 ticket。这属于最后的兜底手段仅当重构成本极高且阻塞其他工作时才应使用。作为对照src/mongo/BUILD.bazel中已有的idl_headers文件组src/mongo/BUILD.bazel#L311展示了公共头文件组的标准写法集中列出一批头文件标签供生成类规则统一引用。core_headers遵循同样的 filegroup 模式但只承载这种不得已的例外头文件。8. 小结MongoDB 仓库的 Bazel 开发工作流可以概括为三条铁律文件必须静态声明不使用glob/通配符新增文件手动加入srcs/hdrs依赖必须显式声明通过deps用:local、//abs/path:target或subdir:target标签表达依赖关系优先使用专用宏mongo_cc_binary、mongo_cc_library、idl_generator已封装好全局依赖与头文件推导等 MongoDB 特有逻辑。遇到头文件归属问题时先用bazel build //src/...让构建器指出缺失位置再决定是补deps还是补hdrs必要时才动用core_headers兜底并登记 SERVER ticket。这套工作流保证了百万行级代码库在静态依赖图下的构建速度与可查询性。【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考