MongoDB 仓库内置 Abseil:从 add_subdirectory 到传统安装的 CMake 构建全指南
2026/9/15 16:38:06 网站建设 项目流程

MongoDB 仓库内置 Abseil:从 add_subdirectory 到传统安装的 CMake 构建全指南

【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo

导读

Abseil 是 Google 开源的 C++ 公共库集合,MongoDB 以源码形式将其内置在src/third_party/abseil-cpp/dist目录下。Abseil 随仓库自带一套完整的 CMake 构建脚本(入口为 CMakeLists.txt),可在 Linux、macOS、Windows 等广泛平台上使用,这也是 CMake 中 "C" 代表 cross-platform(跨平台)的由来。本文基于 Abseil 官方构建文档 CMake/README.md,系统讲解两种主流接入方式——嵌入子目录(add_subdirectory传统安装(build + install +find_package,并逐项拆解全部 CMake 配置开关及其在源码中的真实实现,帮助你在一小时内把 Abseil 正确接入自己的 CMake 工程并跑通测试。

一、两种接入方式怎么选

Abseil 的 CMake 构建脚本会在配置期根据当前工程形态自动决定行为,这一点在 CMakeLists.txt 中有直接体现:

# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp)) # in the source tree of a project that uses it, install rules are disabled. if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) option(ABSL_ENABLE_INSTALL "Enable install rule" OFF) else() option(ABSL_ENABLE_INSTALL "Enable install rule" ON) endif()

即:当 Abseil 作为子项目被add_subdirectory()引入时,ABSL_ENABLE_INSTALL默认自动关闭;只有当 Abseil 本身就是顶层工程时才默认开启安装规则。

出于API/ABI 兼容性的考虑,官方强烈建议把 Abseil 构建在你的项目子目录中(或作为嵌入式依赖),而不是单独安装后全局使用。原因在于:Abseil 的编译选项、absl::base/options.h中的 ABI 开关会随编译环境变化,独立安装的 Abseil 与被调用的代码可能因编译标准不一致而产生 ABI 撕裂。因此:

使用场景推荐方式
中小型应用、希望快速上手拷贝或 git submodule 到子目录,add_subdirectory引入
大型工程、多项目共享同一版本传统安装模式,install 后find_package(absl)

二、方式一:通过 add_subdirectory 嵌入项目

2.1 四个步骤

  1. 准备测试依赖:如果想构建 Abseil 自带的测试,需要先把 Google Test 集成进 CMake 工程;若不需要测试,配置时传-DBUILD_TESTING=OFF-DABSL_BUILD_TESTING=OFF即可。
  2. 放置源码:把 Abseil 下载后拷贝进 CMake 工程的子目录,或以 git submodule 方式挂载(MongoDB 仓库即采用"内置源码目录"的等价形态,位于src/third_party/abseil-cpp/dist)。
  3. 引入目标:用 CMake 命令add_subdirectory(abseil-cpp)把 Abseil 直接包含进当前工程。
  4. 链接库:把要使用的absl::目标加入可执行文件或库的target_link_libraries()段。

2.2 应用工程完整示例

以下 CMakeLists.txt 是官方文档给出的应用工程示例,可直接复制使用:

cmake_minimum_required(VERSION 3.16) project(my_app_project) # Pick the C++ standard to compile with. # Abseil currently supports C++17 and C++20. set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_subdirectory(abseil-cpp) add_executable(my_exe source.cpp) target_link_libraries(my_exe absl::base absl::synchronization absl::strings)

需要注意:CMake 3.16 是 Abseil 官方支持的最低版本,CMakeLists.txt 第 19 行即写有cmake_minimum_required(VERSION 3.16);C++ 标准方面,Abseil 目前支持 C++17 与 C++20。

absl::前缀目标并非手工创建的"占位名",而是在 AbseilHelpers.cmake 中通过别名机制统一导出:

add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME})

所以absl::baseabsl::stringsabsl::synchronization等名字与源码中的实际 target 一一对应,链接时不会产生重名冲突。

2.3 库开发者:把 C++ 标准决策权留给顶层应用

如果你开发的是一个面向其他客户端使用的库,则不应在库内直接设置全局CMAKE_CXX_STANDARD,而应把它留空(或仅在作为顶层工程构建时才设置),并把最低 C++ 标准约束在 target 层面。官方文档给出的标准做法如下:

cmake_minimum_required(VERSION 3.16) project(my_lib_project) # Leave C++ standard up to the root application, so set it only if this is the # current top-level CMake project. if(CMAKE_SOURCE_DIR STREQUAL my_lib_project_SOURCE_DIR) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) endif() add_subdirectory(abseil-cpp) add_library(my_lib source.cpp) target_link_libraries(my_lib absl::base absl::synchronization absl::strings) # Enforce that my_lib requires C++17. Important to document for clients that they # must set CMAKE_CXX_STANDARD to 17 or higher for proper Abseil ABI compatibility # (since otherwise, Abseil library targets could be compiled with a lower C++ # standard than my_lib). target_compile_features(my_lib PUBLIC cxx_std_17) if(CMAKE_CXX_STANDARD LESS 17) message(FATAL_ERROR "my_lib_project requires CMAKE_CXX_STANDARD >= 17 (got: ${CMAKE_CXX_STANDARD})") endif()

其中的关键点在最后几行:通过target_compile_features(my_lib PUBLIC cxx_std_17)把 C++17 要求传播给所有下游使用者,同时用CMAKE_CXX_STANDARD LESS 17做显式校验,防止 Abseil 库目标被编译成比my_lib更低的标准,从而规避 ABI 不兼容。

这一设计的底层支撑是ABSL_PROPAGATE_CXX_STD选项(默认 ON)。在 AbseilHelpers.cmake 中,每个 Abseil 库目标都会执行:

if(ABSL_PROPAGATE_CXX_STD) # Abseil libraries require C++17 as the current minimum standard. When # compiled with a higher standard (either because it is the compiler's # default or explicitly requested), then Abseil requires that standard. target_compile_features(${_NAME} PUBLIC ${ABSL_INTERNAL_CXX_STD_FEATURE}) endif()

即每个absl::目标都带PUBLIC的编译特性要求,会把所需 C++ 标准自动传播给链接它的上层目标。因此只要上层应用设置一个足够高且一致的CMAKE_CXX_STANDARD,整条依赖链的编译标准就是统一的。

三、运行 Abseil 自带测试

3.1 启用测试

使用-DABSL_BUILD_TESTING=ON即可构建 Abseil 的测试,但前提是BUILD_TESTING也必须为 ON(默认即为 ON)。在 CMakeLists.txt 中可看到:

option(ABSL_BUILD_TESTING "If ON, Abseil will build all of Abseil's own tests." OFF) option(ABSL_BUILD_TEST_HELPERS "If ON, Abseil will build libraries that you can use to write tests against Abseil code. This option requires that Abseil is configured to use GoogleTest." OFF)

注意ABSL_BUILD_TESTING默认是 OFF,与ABSL_BUILD_TEST_HELPERS(构建可供你编写针对 Abseil 代码测试的辅助库)相互独立。

3.2 提供 Google Test 依赖的两种方式

官方提供了两条路,任选其一:

  • -DABSL_USE_GOOGLETEST_HEAD=ON:在 CMake 配置阶段自动把最新版 Google Test 源码下载到构建目录,并与 Abseil 测试一起编译。背后的实现是 DownloadGTest.cmake,它先configure_file生成外部工程,再execute_process完成配置与构建,最后add_subdirectory引入gtestgtest_main等目标。
  • 手动集成 Google Test:参照 Googletest 官方 CMake 使用说明,把 Googletest 作为依赖接入你的构建。

需要留意的是,这两个选项存在互斥校验:在 CMakeLists.txt 中,若同时设置了ABSL_USE_GOOGLETEST_HEADABSL_GOOGLETEST_DOWNLOAD_URL,配置阶段会直接FATAL_ERROR报错。

3.3 只跑 Abseil 测试的最小脚本

官方文档提供了如下可直接执行的完整脚本:

cd path/to/abseil-cpp mkdir build cd build cmake -DABSL_BUILD_TESTING=ON -DABSL_USE_GOOGLETEST_HEAD=ON .. make -j ctest

按此流程,make -j会同时编译 Abseil 库与其测试二进制,ctest则执行全部注册的测试用例并输出汇总结果。需要说明的适用前提是:目前 Abseil 团队仅在 Linux 环境下通过 CMake 跑测试,其他平台的支持仍在推进中。

四、方式二:传统 CMake 安装流程(build + install + find_package)

对于更大的工程,官方推荐"分离构建"的传统模式:先单独构建、安装 Google Test 与 Abseil,再让使用方通过find_package消费。

4.1 第一步:构建并安装 Google Test

cmake -S /source/googletest -B /build/googletest -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/installation/dir -DBUILD_GMOCK=ON cmake --build /build/googletest --target install

4.2 第二步:配置并构建 Abseil

配置时必须同时开启ABSL_USE_EXTERNAL_GOOGLETESTABSL_FIND_GOOGLETESTABSL_ENABLE_INSTALL

cmake -S /source/abseil-cpp -B /build/abseil-cpp -DCMAKE_PREFIX_PATH=/installation/dir -DCMAKE_INSTALL_PREFIX=/installation/dir -DABSL_ENABLE_INSTALL=ON -DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON cmake --build /temporary/build/abseil-cpp

参数含义:CMAKE_PREFIX_PATH指定 Google Test 已安装的位置;CMAKE_INSTALL_PREFIX指定 Abseil 的目标安装位置,二者可以不同。

4.3 第三步:跑测试并安装

ctest --test-dir /temporary/build/abseil-cpp cmake --build /temporary/build/abseil-cpp --target install

--target install执行后,Abseil 会把头文件、编译产物与 CMake package 配置安装到安装前缀下。仓库中的集成测试脚本 install_test_project/test.sh 完整复现了这一流程:先curl下载指定版本的 Googletest 压缩包并安装,再以-DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON -DABSL_BUILD_TESTING=ON构建安装 Abseil,随后ctest验证,最后用find_package(absl)编译一个调用absl::stringssimple可执行程序并校验输出。

4.4 消费方:find_package(absl)

安装完成后,使用方工程只需:

cmake_minimum_required(VERSION 3.16) project(absl_cmake_testing CXX) add_executable(simple simple.cc) find_package(absl REQUIRED) target_link_libraries(simple absl::strings absl::config)

这正是仓库中 install_test_project/CMakeLists.txt 的实际内容。安装时生成并写入lib/cmake/absl/abslConfig.cmake(模板见 abslConfig.cmake.in)会依次完成find_dependency(Threads)@PACKAGE_INIT@展开并include对应的abslTargets.cmake,从而把absl::strings等带absl::命名空间的目标导出给消费方。

值得一提的细节:安装流程会生成一份options-pinned.h并替换安装目录下的absl/base/options.h。在 CMakeLists.txt 中,CMake 会根据当前编译标准把ABSL_OPTION_USE_STD_*宏从"自动检测(值 2)"改写为"使用标准库(值 1)"或"禁用(值 0)"——这正是保证安装版 ABI 与编译标准一致的关键机制,也是官方建议"安装版务必保证CMAKE_CXX_STANDARD >= 17"的底层原因。

五、CMake 选项速查表

综合官方文档与 CMakeLists.txt 源码,全部相关开关汇总如下:

选项默认值作用
ABSL_ENABLE_INSTALL顶层工程 ON / 子项目 OFF是否启用安装规则;作为子项目被add_subdirectory引入时自动关闭
ABSL_BUILD_TESTINGOFF是否构建 Abseil 自身全部测试,需与BUILD_TESTING=ON(默认)同时成立
ABSL_BUILD_TEST_HELPERSOFF是否构建供外部编写针对 Abseil 代码测试的辅助库
ABSL_USE_EXTERNAL_GOOGLETESTOFFON 时假定 GoogleTest 目标已由包含方工程提供(适用于add_subdirectory场景)
ABSL_FIND_GOOGLETEST依赖ABSL_USE_EXTERNAL_GOOGLETEST,默认 ONON 时用find_package(GTest)查找已安装的 Google Test
ABSL_USE_GOOGLETEST_HEADOFFON 时配置阶段自动下载最新 Google Test(main.zip)源码到构建目录
ABSL_GOOGLETEST_DOWNLOAD_URL指定从某个 ZIP 地址下载特定版本的 Google Test
ABSL_LOCAL_GOOGLETEST_DIR/usr/src/googletest前两者均未设置时,使用本地已检出的 Google Test 目录
ABSL_PROPAGATE_CXX_STDON通过target_compile_features(... PUBLIC/INTERFACE ...)把所需 C++ 标准传播给链接方
ABSL_BUILD_MONOLITHIC_SHARED_LIBSOFF将 Abseil 构建为单一共享库(Windows 上始终启用);未设置BUILD_SHARED_LIBS时会被忽略并告警
ABSL_USE_SYSTEM_INCLUDESOFF把 Abseil 头文件标记为 SYSTEM include 以静默其内部警告
ABSL_MSVC_STATIC_RUNTIMEOFF链接静态运行时库(MSVC 专用)

六、可用的 Abseil CMake 公共目标(摘录)

以下为官方文档给出的非穷尽公共目标清单,均可直接在target_link_libraries中使用:

absl::algorithm absl::base absl::debugging absl::flat_hash_map absl::flags absl::memory absl::meta absl::numeric absl::random_random absl::strings absl::synchronization absl::time absl::utility

如需完整目标清单,可查阅 Abseil 源码各模块下的 CMake 声明(每个库模块通过absl_cc_library(...)宏定义并自动生成absl::别名,宏定义位于 AbseilHelpers.cmake)。MongoDB 工程中也大量使用absl::stringsabsl::base等目标,读者可直接参考仓库内 src/third_party/abseil-cpp/dist/CMakeLists.txt 观察各目标的组织方式。

七、小结

  • 应用接入add_subdirectory(abseil-cpp)+target_link_libraries(my_exe absl::strings ...),并设置CMAKE_CXX_STANDARD 17/20,三步即完成集成。
  • 库的接入:把 C++ 标准约束下沉到target_compile_features,并校验CMAKE_CXX_STANDARD >= 17,保证 ABI 一致。
  • 跑测试-DABSL_BUILD_TESTING=ON,配合ABSL_USE_GOOGLETEST_HEAD(自动下载)或外部/本地 Google Test。
  • 传统安装:依次安装 Google Test 与 Abseil(开启ABSL_ENABLE_INSTALLABSL_USE_EXTERNAL_GOOGLETESTABSL_FIND_GOOGLETEST),消费方find_package(absl)即可。
  • 排错入口:安装版 ABI 由构建期生成的options-pinned.h钉死,务必保证全链路的CMAKE_CXX_STANDARD一致;互斥选项(如ABSL_USE_GOOGLETEST_HEADABSL_GOOGLETEST_DOWNLOAD_URL同开)会在配置期直接报错。

所有结论均可在 MongoDB 仓库内置的 Abseil 源码 CMake/README.md、CMakeLists.txt、AbseilHelpers.cmake 及 install_test_project/test.sh 中直接验证,按上述流程操作即可在本地工程中稳定复现。

【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询