首页
/ Protocol Buffers CMake 构建系统实战:配置、编译、测试与安装全流程解析

Protocol Buffers CMake 构建系统实战:配置、编译、测试与安装全流程解析

2026-09-05 15:09:37作者:裘旻烁

本文基于 protobuf 仓库中的 cmake/README.md 展开,系统讲解如何使用 CMake 完成 protobuf 的源码获取、跨平台配置、编译、测试与安装,并结合 CMakeLists.txt 及各 cmake/*.cmake 脚本的源码实现,深入剖析每个构建选项的底层行为与依赖管理机制,帮助你在 Windows 和 Linux 上稳定构建出可复用的 libprotobuf、libprotoc 与 protoc 产物。

一、前提条件与源码获取

README 明确了构建 protobuf 的三件前置工具:

  1. CMake:当前支持 CMake 3.22 及以上版本。需要注意的是,CMakeLists.txt 中声明的最低版本为 cmake_minimum_required(VERSION 3.16...3.26),即脚本本身允许从 3.16 开始解析(并兼容到 3.26 的 policy 行为),但官方文档建议以 3.22+ 为准以获得完整特性。
  2. Git:用于克隆源码仓库。
  3. Abseil:如果系统未安装 Abseil,配置阶段会自动从 GitHub 拉取(拉取逻辑见下文“依赖管理”小节)。

获取源码有两种方式:从 release 页面下载最新的稳定源码包,或使用 git 克隆指定标签或分支:

git clone -b [release_tag] https://gitcode.com/GitHub_Trending/pr/protobuf

其中 [release_tag] 可以是类似 v32.0-rc1 的发布标签,也可以是 main 等分支名(用于获取最新代码)。

二、基础构建流程

README 推荐的良好实践是不要在源码树内直接构建,而是使用独立的构建目录。标准跨平台流程如下(在 protobuf 源码根目录执行):

# 1. 配置:输出到 build 目录,安装到 ../install,Release 构建
cmake -S . -B build \
  -DCMAKE_INSTALL_PREFIX=../install \
  -DCMAKE_BUILD_TYPE=Release

# 2. 编译(10 个并行任务)
cmake --build build --parallel 10

# 3. 运行测试
ctest --test-dir build --verbose

# 4. 安装库与头文件
cmake --install build

执行完成后,编译出的库、头文件与 protoc 可执行文件会安装到相对于源码根目录的 ../install 目录中。

从源码结构看,配置阶段的行为由 CMakeLists.txt 主控:

三、CMake 配置标志详解

以下标志在配置步骤通过 cmake -S . -B build -D<FLAG>=<VALUE> 传入。所有 protobuf_* 选项的默认值集中定义在 CMakeLists.txt,另有少量高级选项位于 cmake/protobuf-options.cmake

3.1 C++ 标准版本

默认情况下 CMake 使用系统默认 C++ 标准。由于 protobuf 要求 C++17 或更新标准,有时需要显式覆盖:

# 配置以 C++17 构建 protobuf
cmake . -DCMAKE_CXX_STANDARD=17

这一点在源码中有硬性校验:CMakeLists.txtCMAKE_CXX_STANDARD 低于 17 时直接 FATAL_ERROR 报错退出,因此低于 C++17 的配置无法通过。

3.2 依赖管理:Abseil 与 Google Test

配置阶段可以告诉 CMake 在哪里寻找已安装的 Abseil、Google Test 和 jsoncpp;如果找不到,会从 GitHub 拉取源码并构建。指定本地依赖位置的方式是设置 -DCMAKE_PREFIX_PATH

# 指向 Abseil 与 GTest 的安装位置
cmake . -DCMAKE_PREFIX_PATH=/path/to/my/dependencies

依赖拉取的完整逻辑可以对照源码理解:

  • Abseilcmake/abseil-cpp.cmake 先尝试 find_package(absl CONFIG)protobuf_FORCE_FETCH_DEPENDENCIES 开启时跳过本地查找);找不到且 protobuf_LOCAL_DEPENDENCIES_ONLY 未开启时,通过 FetchContentabseil-cpp 仓库拉取指定版本。若开启安装,Abseil 会随 protobuf 一并安装(ABSL_ENABLE_INSTALL ON)。
  • Google Testcmake/gtest.cmake 同理——先 find_package(GTest CONFIG),找不到则 FetchContent 拉取 googletest。注意该脚本只在 protobuf_BUILD_TESTS=ON 时才会被 include(见 CMakeLists.txt)。
  • 版本锚定:拉取时使用的版本号定义在 cmake/dependencies.cmake,例如当前仓库锁定 Abseil 20250512.1、Google Test 1.17.0。该文件注释说明它由 Bazel 配置自动生成,改动会被覆盖。

两个互斥的依赖策略开关(定义于 CMakeLists.txt):

选项 作用
protobuf_LOCAL_DEPENDENCIES_ONLY=ON 禁止从 GitHub 下载任何依赖,依赖必须已作为安装包本地存在;找不到即为错误
protobuf_FORCE_FETCH_DEPENDENCIES=ON 强制从 GitHub 下载所有依赖,忽略本地安装

两者同时设置会被 FATAL_ERROR 拒绝(见 CMakeLists.txt)。

3.3 启用测试

构建单元测试需要显式开启:

  • -Dprotobuf_BUILD_TESTS=ON

开启后,CMakeLists.txt 会执行 enable_testing() 并 include cmake/tests.cmake。从 cmake/tests.cmake 可以看到,测试体系会编译出以下可执行目标:tests(完整功能测试)、lite-test(lite 运行时测试)、upb-test(upb 后端测试,依赖 protobuf_BUILD_LIBUPB)、fake_plugintest_plugin(protoc 插件机制测试),并通过 add_test 注册为 full-testlite-testupb-test 等 ctest 用例,工作目录均设置为源码根目录。

此外,测试相关还有一组高级选项:

  • protobuf_BUILD_CONFORMANCE=ON:构建一致性(conformance)测试,见 cmake/conformance.cmake
  • protobuf_TEST_XML_OUTDIR=<dir>:为 GTest 附加 --gtest_output=xml:<dir> 参数,输出 XML 测试日志(见 cmake/tests.cmake)。

3.4 ZLib 支持

如果希望 libprotobuf 中包含 GzipInputStreamGzipOutputStream,需要系统中安装 ZLib,且其头文件与库位于标准系统位置或自定义安装前缀下。非标准位置可通过以下变量帮助 CMake 定位:

  • -DZLIB_INCLUDE_DIR=/path/to/zlib/headers
  • -DZLIB_LIBRARIES=/path/to/zlib/library.lib

源码侧,protobuf_WITH_ZLIB 默认开启(见 CMakeLists.txt)。配置时执行 find_package(ZLIB),找到则定义 HAVE_ZLIB=1 并优先使用 ZLIB::ZLIB 导入目标;找不到时静默置 HAVE_ZLIB=0 而非报错(见 CMakeLists.txt)——这意味着 ZLib 缺失不会中断构建,只是压缩流能力不可用。

3.5 完整构建选项表

除了 README 重点介绍的选项,CMakeLists.txt 还暴露了以下 protobuf_* 开关,实际裁剪构建时非常有用:

选项 默认值 说明
protobuf_INSTALL ON 安装二进制与文件
protobuf_BUILD_TESTS OFF 构建单元测试
protobuf_BUILD_CONFORMANCE OFF 构建一致性测试
protobuf_BUILD_EXAMPLES OFF 构建示例
protobuf_BUILD_PROTOBUF_BINARIES ON 构建全部库与 protoc;设为 OFF 时会自动 find_package(Protobuf NO_MODULE) 复用已安装的 CMake 包
protobuf_BUILD_PROTOC_BINARIES ON 构建 libprotoc 与 protoc
protobuf_BUILD_LIBPROTOBUF ON 构建 libprotobuf
protobuf_BUILD_LIBPROTOC OFF 构建 libprotoc(启用 protoc 或测试时自动强制为 ON,见 CMakeLists.txt
protobuf_BUILD_LIBUPB ON 构建 libupb(构建 protoc 时会自动强制为 ON,见 CMakeLists.txt
protobuf_DISABLE_RTTI OFF 移除二进制中的 RTTI
protobuf_ALLOW_CCACHE OFF 调整构建旗标以支持 ccache(MSVC 下会剥离 /Zi 调试符号,见 CMakeLists.txt
protobuf_USE_UNITY_BUILD OFF 尽力启用 Unity(Jumbo)构建
protobuf_DEBUG_POSTFIX d Debug 构建的库名后缀(仅 Debug 模式附加,见 cmake/install.cmake
protobuf_VERBOSE OFF 输出详细配置日志,见 cmake/protobuf-options.cmake
protobuf_MODULE_COMPATIBLE OFF 兼容 CMake 内置 FindProtobuf.cmake 模块的行为,见 cmake/protobuf-options.cmake

选项之间存在依赖约束,源码会做交叉校验并报错,例如:protobuf_BUILD_LIBPROTOBUF=OFF 时要求同时关闭 protobuf_BUILD_PROTOC_BINARIESprotobuf_BUILD_TESTSprotobuf_BUILD_CONFORMANCEprotobuf_BUILD_EXAMPLESprotobuf_BUILD_LIBUPB(见 CMakeLists.txt);protobuf_BUILD_PROTOBUF_BINARIES=OFF 会连带关闭 protobuf_INSTALL(见 CMakeLists.txt)。

3.6 动态库 vs 静态链接

静态链接是默认行为。 要构建共享库(Windows 上的 DLL),在配置时添加:

  • -Dprotobuf_BUILD_SHARED_LIBS=ON

使用共享库构建自己的项目时,还必须定义 #define PROTOBUF_USE_DLLS。这一点在安装脚本中也有印证:cmake/install.cmakeprotobuf_BUILD_SHARED_LIBS 开启时会向 pkg-config 文件写入 -DPROTOBUF_USE_DLLS 编译旗标。

关于共享构建,源码还揭示了几个关键行为(见 CMakeLists.txtCMakeLists.txt):

  • 共享构建时全局设置 CMAKE_POSITION_INDEPENDENT_CODE ON,并强制 Abseil 也以共享库构建,避免 ODR 违规;
  • Windows(MSVC)下共享构建会把所有二进制输出统一放到 build/bin,保证 DLL 与可执行文件同目录;
  • MSVC 静态构建默认链接静态运行时(protobuf_MSVC_STATIC_RUNTIMECMAKE_MSVC_RUNTIME_LIBRARY 设为 MultiThreaded 系列),但若外部项目已通过 add_subdirectory/FetchContent 消费 protobuf 并显式设置了运行时旗标,脚本不会覆盖,以避免 LNK2038 类运行时不匹配错误(见 CMakeLists.txt);
  • Windows 共享库构建还启用了 CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON(见 CMakeLists.txt)。

四、编译

跨平台编译的标准命令:

cmake --build <build_directory>
# 例如
cmake --build build --parallel 10

如果生成器支持多配置(如 Visual Studio),必须额外指定配置类型:

cmake --build build --config Release

五、运行测试

先按上文编译,然后用 ctest 执行:

ctest --test-dir build --progress --output-on-failure

也可以构建 check 目标,它会完成测试的编译与运行:

cmake --build build --target check

如需运行特定测试,则要把参数传给测试程序本身,需要在构建目录中找到对应的测试可执行文件(如 testslite-testupb-test,均注册于 cmake/tests.cmake),再按 GTest 约定追加 --gtest_filter 等参数。

六、安装

将 protobuf 安装到配置时指定的 CMAKE_INSTALL_PREFIX 目录,构建 install 目标即可:

cmake --build <build_directory> --target install

安装后会在目标位置生成以下目录:

  • binprotoc 编译器(当启用 protobuf_BUILD_LIBUPB 时还会附带 protoc-gen-upbprotoc-gen-upbdefsprotoc-gen-upb_minitable 插件,见 cmake/install.cmake);
  • include:C++ 头文件与 .proto 文件;
  • lib:链接库与 CMake 包配置文件。

安装脚本 cmake/install.cmake 中还包含若干值得注意的细节:

  • 为 Linux 设置 INSTALL_RPATH "$ORIGIN"、为 macOS 设置 @loader_pathprotoc 等可执行文件则指向 ../lib,以便从任意位置运行(见 cmake/install.cmake);
  • 生成并安装 pkg-config 文件 protobuf.pcprotobuf-lite.pcupb.pc(见 cmake/install.cmake);
  • CMake 包配置默认安装到 ${CMAKE_INSTALL_LIBDIR}/cmake/protobuf,可通过缓存变量 protobuf_CMAKE_SUBDIR 调整(见 cmake/install.cmake),随后导出 protobuf:: 命名空间的目标(cmake/install.cmake)。

七、平台特定细节

7.1 Windows 构建

Windows 上可以使用 Visual Studio 的命令行工具或 IDE 构建。

生成器(Generators):对 Windows 开发者最有用的两类生成器:

  • Visual Studio:生成多配置 .sln 文件,示例 -G "Visual Studio 16 2019"
  • Ninja:使用外部工具 Ninja 构建,往往是最快的方案。

环境准备:从 开始 菜单打开对应的 命令提示符(例如 x86 Native Tools Command Prompt for VS 2019),确保 cl.exe 等构建工具在 PATH 中。

Windows 上 DLL vs 静态链接:虽然可以构建共享库,但在 Windows 上强烈建议静态链接。原因有二:Win32 中每个 DLL 与宿主二进制使用独立堆,以及不同版本 MSVC STL 之间的二进制兼容性问题。若分发软件,不要libprotobuf.dlllibprotoc.dll 装到共享位置,应保留在应用自己的安装目录内。

编译器警告说明:构建 protobuf 库时禁用了以下 MSVC 警告,你的项目可能需要同样禁用:

  • C4065:switch 语句包含 'default' 但没有 'case' 标签
  • C4146:一元负号作用于无符号类型
  • C4244:'conversion' 从 'type1' 到 'type2' 的转换可能丢失数据
  • C4251:'identifier':类 'type' 需要 dll-interface 才能被 'type2' 的客户端使用
  • C4267:'var':从 'size_t' 到 'type' 的转换可能丢失数据
  • C4305:'identifier':从 'type1' 到 'type2' 的截断
  • C4307:'operator':整型常量溢出
  • C4309:'conversion':常量值截断
  • C4334:'operator':32 位移位结果隐式转换为 64 位
  • C4355:'this':用于基类成员初始化列表
  • C4506:内联函数 'function' 无定义
  • C4800:'type':强制转换为 bool(性能警告)
  • C4996:编译器遇到弃用声明

其中 C4251 在把 protobuf 构建为 DLL 时尤为值得注意。此外,测试代码在 MSVC 下还会额外附加 /wd4146/bigobj 编译旗标(见 cmake/tests.cmake),静态链接时会追加 /ignore:4221 抑制“无符号定义”链接器警告(见 CMakeLists.txt)。

7.2 Linux 构建

Linux 上的 CMake 构建流程几乎相同,需要安装 gccclang。CMake 默认生成 Makefiles,也可配置为 Ninja。构建完成后,可以用 sudo 全局安装:

sudo cmake --install build

或直接使用 Makefiles:

cd build
sudo make install

Linux 下另一个值得了解的源码细节是 CMakeLists.txt 会探测链接器是否支持 --version-scriptprotobuf_HAVE_LD_VERSION_SCRIPT),用于配合 src/libprotobuf.mapsrc/libprotobuf-lite.mapsrc/libprotoc.map 等符号版本脚本控制共享库导出符号;同时会检测编译器是否具备内建 64 位原子操作,不具备则链接 libatomic(适用于 32 位 PowerPC 等平台,见 CMakeLists.txt)。

八、小结

protobuf 的 CMake 构建体系以 CMakeLists.txt 为总控,通过一组 protobuf_* 选项精确裁剪“建什么、测什么、装什么”,依赖管理则采用“本地 find_package 优先、GitHub FetchContent 兜底”的策略,且可用 protobuf_LOCAL_DEPENDENCIES_ONLY / protobuf_FORCE_FETCH_DEPENDENCIES 两个互斥开关将策略固化为错误条件。掌握本文的配置标志表、依赖链路与平台注意事项后,你可以在 Windows(MSVC/VS 生成器,建议静态链接)和 Linux(gcc/clang + Makefiles 或 Ninja)上完成 protobuf 的完整构建、测试与分发。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384