CMake中protobuf_generate执行成功但未生成代码求助
使用CMake v3.26.4构建基于gRPC的C11项目,已从源码编译gRPC并关联proto文件处理步骤,CMake配置无错误提示,但始终未生成.pb/.grpc.pb对应的C头文件和源文件,全磁盘搜索无果;已通过官方protoc工具验证.proto文件语法正确且可生成服务定义。
项目文件结构
root/ ├─CMakeList.txt ├─service/ | ├─CMakeLists.txt | ├─proto | ├─CMakeLists.txt | ├─service.proto ├─third_party | ├─CMakeLists.txt | ├─grpc | ├─abseil
proto目录下的CMakeLists.txt内容
find_package(Threads REQUIRED) if(MSVC) add_definitions(-D_WIN32_WINNT=0x600) endif() # Link in third_party libraries needed for code generation target_link_libraries(my_project PRIVATE protobuf grpc++ grpc_plugin_support) # Get the environment variables needed for later. set(pb_cmake ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/third_party/grpc/third_party/protobuf/cmake/protobuf/protobuf-generate.cmake) message("protobuf_generate function defined at ${pb_cmake}") #for sanity check include(${pb_cmake}) target_include_directories(cengine PRIVATE ${_GRPC_CPP_PLUGIN_INCLUDE_DIRS}) set(grpc_cpp_plugin_location $<TARGET_FILE:grpc_cpp_plugin>) message("gRPC plugin is at ${grpc_cpp_plugin_location}") #for sanity check # Protobuf/Grpc source files set(PROTO_SRC_DIR ${PROJECT_SOURCE_DIR}/service/proto) set(PROTO_GEN_DIR ${PROJECT_SOURCE_DIR}/gen) set(PROTO_FILES ${PROTO_SRC_DIR}/first_service.proto ${PROTO_SRC_DIR}/second_service.proto ) # Add Library target with protobuf sources add_library(service_proto OBJECT ${PROTO_FILES}) target_link_libraries(service_proto PUBLIC protobuf::libprotobuf grpc grpc++ ) target_include_directories(service_proto PUBLIC ${PROTO_GEN_DIR}) # Compile protobuf and grpc files in myproto target to cpp protobuf_generate( TARGET service_proto LANGUAGE cpp GENERATE_EXTENSIONS .pb.hpp .pb.cpp PROTOC_OUT_DIR "${PROTO_GEN_DIR}" ) protobuf_generate( TARGET service_proto LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.hpp .grpc.pb.cpp PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}" PROTOC_OUT_DIR "${PROTO_GEN_DIR}" )
CMake执行输出
>cmake -B ../out -S . -G "MinGW Makefiles" -- -- 23.0.0 CMake Deprecation Warning at third_party/grpc/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. protobuf_generate function defined at [REDACTED] gRPC plugin is at $<TARGET_FILE:grpc_cpp_plugin> -- Configuring done (1.2s) -- Generating done (13.5s) -- Build files have been written to: C:/src/out
排查与解决思路
1. 确认代码生成的触发时机
protobuf_generate默认不会在CMake配置阶段生成代码,而是在构建阶段(执行make/ninja等命令时)触发protoc编译。仅执行cmake配置不会生成文件,需进入out目录运行构建命令:
mingw32-make
之后检查gen目录是否生成目标文件。
2. 修正gRPC插件路径的延迟展开问题
CMake输出中gRPC plugin is at $<TARGET_FILE:grpc_cpp_plugin>是生成器表达式,该表达式仅在构建阶段解析为实际路径,但protobuf_generate的PLUGIN参数在配置阶段就需要明确路径,直接使用会导致protoc找不到插件。
修改方式:
# 替换原grpc_cpp_plugin_location设置,通过find_program获取插件实际路径 find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin HINTS ${CMAKE_BINARY_DIR}/third_party/grpc/bin)
然后在protobuf_generate的PLUGIN参数中使用:
PLUGIN "protoc-gen-grpc=${GRPC_CPP_PLUGIN}"
3. 确保生成目录存在且有权限
- CMake不会自动创建
PROTO_GEN_DIR,需手动添加创建命令:
file(MAKE_DIRECTORY ${PROTO_GEN_DIR})
- 检查Windows系统下
${PROJECT_SOURCE_DIR}/gen目录的读写权限,避免因权限问题导致文件无法生成。
4. 显式关联proto文件到生成命令
尝试在protobuf_generate中显式指定PROTO_FILES参数,避免自动查找的潜在问题:
protobuf_generate( TARGET service_proto LANGUAGE cpp GENERATE_EXTENSIONS .pb.hpp .pb.cpp PROTOC_OUT_DIR "${PROTO_GEN_DIR}" PROTO_FILES ${PROTO_FILES} ) protobuf_generate( TARGET service_proto LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.hpp .grpc.pb.cpp PLUGIN "protoc-gen-grpc=${GRPC_CPP_PLUGIN}" PROTOC_OUT_DIR "${PROTO_GEN_DIR}" PROTO_FILES ${PROTO_FILES} )
5. 启用构建日志排查细节
执行构建命令时开启详细日志,查看protoc的具体调用情况,排查隐藏错误:
mingw32-make VERBOSE=1
通过日志可确认protoc是否被正确调用、插件路径是否有效、输出目录是否正确等。
6. 修正无关目标的引用问题
原CMakeLists中target_link_libraries(my_project ...)和target_include_directories(cengine ...)中的my_project、cengine目标若未在当前CMakeLists中定义,需移除这些无关语句(或确保上级目录已正确导出这些目标),避免干扰proto生成流程。
内容的提问来源于stack exchange,提问作者user5859728

