You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CMake FetchContent拉取Protobuf和gRPC并构建时编译(封闭构建)

问题

我正在撰写一篇gRPC相关博客,希望读者无需全局安装Protobuf和gRPC即可运行示例代码,因此尝试完全借助CMake的FetchContent下载、编译Protobuf和gRPC,并将其用于项目代码构建(用户仅需复制粘贴CMakeLists.txt)。但编译时出现大量错误,以下是我的CMakeLists.txt代码:

cmake_minimum_required(VERSION 3.15)
project(command_server)

include(FetchContent)
FetchContent_Declare(
  absl
  GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
  GIT_TAG        origin/master
  OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(absl)

FetchContent_Declare(Protobuf
  GIT_REPOSITORY git@github.com:protocolbuffers/protobuf.git
  GIT_TAG        v23.3
  SOURCE_SUBDIR  cmake
  OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(Protobuf)

FetchContent_Declare(
  gRPC
  GIT_REPOSITORY git@github.com:grpc/grpc
  GIT_TAG        v1.55.1  # e.g v1.28.0
  OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(gRPC)

find_package(absl REQUIRED)
FetchContent_GetProperties(Protobuf SOURCE_DIR Protobuf_SOURCE_DIR)
include(${Protobuf_SOURCE_DIR}/cmake/protobuf-generate.cmake)

add_library(proto OBJECT "${CMAKE_CURRENT_LIST_DIR}/helloworld.proto")
target_link_libraries(proto PUBLIC protobuf::libprotobuf)
set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
target_include_directories(proto PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>")

protobuf_generate(
    TARGET proto
    LANGUAGE grpc
    GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc
    PLUGIN "protoc-gen-grpc=$<TARGET_FILE:grpc_cpp_plugin>"
    IMPORT_DIRS ${PROTO_IMPORT_DIRS}
    PROTOC_OUT_DIR "${PROTO_BINARY_DIR}")

add_executable(my_exe greater_server.cc)
target_link_libraries(my_exe grpc++ proto)

编译时出现如下错误:

CMake Warning at build/_deps/absl-src/CMakeLists.txt:77 (message):
  A future Abseil release will default ABSL_PROPAGATE_CXX_STD to ON for CMake
  3.8 and up.  We recommend enabling this option to ensure your project still
  builds correctly.


--
-- 23.1.0
CMake Deprecation Warning at build/_deps/grpc-src/third_party/zlib/CMakeLists.txt:1 (cmake_minimum_required):
  Compatibility with CMake < 2.8.12 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value or use a ...<max> suffix to tell
  CMake that the project does not need compatibility with older versions.


-- Found systemd via pkg-config.
-- Configuring done
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotobuf-lite" which requires target "absl_absl_check" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotobuf-lite" which requires target "absl_absl_log" that is not in any export set.

... snipped ...

CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_memory" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_node_hash_map" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_node_hash_set" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_optional" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_span" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_status" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_statusor" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_strings" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_synchronization" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_time" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_type_traits" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_utility" that is not in any export set.
CMake Error: install(EXPORT "protobuf-targets" ...) includes target "libprotoc" which requires target "absl_variant" that is not in any export set.
CMake Error: install(EXPORT "utf8_range-targets" ...) includes target "utf8_validity" which requires target "absl_strings" that is not in any export set.
-- Generating done
CMake Generate step failed.  Build files cannot be regenerated correctly.
解决思路

核心问题分析

错误本质是Protobuf导出目标时,依赖的Abseil组件未被正确纳入导出集合,同时存在版本不匹配、FetchContent加载顺序错误、依赖安装配置冲突等问题,具体修复步骤如下:

1. 统一依赖版本,消除兼容性冲突

  • gRPC v1.55.1官方适配的Protobuf版本为v23.3(当前版本选择正确),但Abseil不能使用origin/master分支,必须指定gRPC和Protobuf兼容的特定版本:gRPC v1.55.1对应的Abseil版本是20230125.3。
  • 将Git仓库地址替换为HTTPS格式,避免用户需要配置SSH密钥才能克隆代码。

2. 调整FetchContent加载顺序

gRPC内部依赖Protobuf和Abseil,正确加载顺序应为:先加载Abseil,再加载Protobuf,最后加载gRPC。同时:

  • 无需手动调用find_package(absl REQUIRED),FetchContent_MakeAvailable会自动完成依赖配置。
  • 移除OVERRIDE_FIND_PACKAGE选项,对于博客示例,直接让FetchContent管理所有依赖更稳妥,避免覆盖系统已有包引发冲突。

3. 配置Abseil的C++标准传播

根据Abseil的警告提示,设置ABSL_PROPAGATE_CXX_STD为ON,确保项目与依赖使用统一的C++标准,避免编译错误。

4. 禁用Protobuf的安装导出(关键修复)

错误根源是Protobuf默认生成安装导出目标,但这些目标依赖的Abseil组件未被包含在导出集中。对于仅本地构建使用的依赖,无需安装,因此禁用相关选项:

  • 设置protobuf_INSTALL为OFF,跳过安装步骤,避免导出目标的问题。
  • 设置protobuf_BUILD_TESTS为OFF,减少编译时间和磁盘占用。
  • 可选设置protobuf_BUILD_SHARED_LIBS控制是否生成动态库。

5. 简化protobuf_generate用法

gRPC和Protobuf已提供成熟的代码生成宏,无需手动导入cmake模块:

  • 无需手动包含protobuf-generate.cmake,FetchContent_MakeAvailable(Protobuf)会自动导入相关模块。
  • 明确分离Protobuf和gRPC代码生成步骤,确保目标配置正确。

修改后的完整CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(command_server)

# 设置统一C++标准,适配依赖要求
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)

# 1. 加载Abseil,使用gRPC v1.55.1兼容的版本
FetchContent_Declare(
  absl
  GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
  GIT_TAG        20230125.3
)
# 启用C++标准传播,确保依赖与项目标准一致
set(ABSL_PROPAGATE_CXX_STD ON)
FetchContent_MakeAvailable(absl)

# 2. 加载Protobuf,禁用安装和测试
FetchContent_Declare(
  Protobuf
  GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
  GIT_TAG        v23.3
  SOURCE_SUBDIR  cmake
)
set(protobuf_BUILD_SHARED_LIBS OFF)
set(protobuf_INSTALL OFF)
set(protobuf_BUILD_TESTS OFF)
FetchContent_MakeAvailable(Protobuf)

# 3. 加载gRPC,禁用测试和安装
FetchContent_Declare(
  gRPC
  GIT_REPOSITORY https://github.com/grpc/grpc.git
  GIT_TAG        v1.55.1
)
set(gRPC_BUILD_TESTS OFF)
set(gRPC_INSTALL OFF)
FetchContent_MakeAvailable(gRPC)

# 获取gRPC C++插件路径
get_target_property(GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin LOCATION)

# 配置proto文件和生成目录
set(PROTO_FILE "${CMAKE_CURRENT_LIST_DIR}/helloworld.proto")
set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")

# 生成Protobuf C++代码
protobuf_generate(
  TARGET proto
  LANGUAGE cpp
  OUT_VAR PROTO_SOURCES
  OUT_DIR ${PROTO_BINARY_DIR}
  PROTOS ${PROTO_FILE}
)

# 生成gRPC C++代码
protobuf_generate(
  TARGET proto
  LANGUAGE grpc
  GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc
  PLUGIN "protoc-gen-grpc=${GRPC_CPP_PLUGIN_EXECUTABLE}"
  OUT_DIR ${PROTO_BINARY_DIR}
  PROTOS ${PROTO_FILE}
)

# 创建proto目标,链接依赖库
add_library(proto OBJECT ${PROTO_SOURCES})
target_link_libraries(proto
  PUBLIC
    protobuf::libprotobuf
    grpc++
)
target_include_directories(proto
  PUBLIC
    $<BUILD_INTERFACE:${PROTO_BINARY_DIR}>
)

# 构建可执行文件,链接依赖
add_executable(my_exe greater_server.cc)
target_link_libraries(my_exe
  PRIVATE
    proto
    grpc++
    grpc++_reflection  # 可选:添加反射支持,方便调试
)

额外说明

  • 添加grpc++_reflection链接,支持服务端反射功能(可根据示例需求移除)。
  • 明确设置C++17标准,这是gRPC和Abseil推荐的最低兼容标准。
  • 禁用所有依赖的测试和安装,大幅减少编译时间和磁盘占用。
  • 替换SSH仓库地址为HTTPS,降低用户环境配置门槛。

内容的提问来源于stack exchange,提问作者Tyler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 23:29:52