如何通过CMake从.proto文件生成Python gRPC Protobuf文件?
问题描述
我用Python开发gRPC服务端,C++实现客户端,需要通过CMake从.proto文件生成Python Protobuf相关文件。手动执行以下命令能正常生成文件:
python3 -m grpc_tools.protoc -I ../protos --python_out=. --pyi_out=. --grpc_python_out=. ../helloworld.proto
但整合到CMakeLists.txt后,始终无法生成目标文件。原CMake配置如下:
cmake_minimum_required(VERSION 3.15) # Project project(myproj) # Protobuf set(protobuf_MODULE_COMPATIBLE TRUE) find_package(Protobuf CONFIG REQUIRED) message(STATUS "Using protobuf ${protobuf_VERSION}") # Protobuf-compiler set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>) # gRPC find_package(gRPC CONFIG REQUIRED) message(STATUS "Using gRPC ${gRPC_VERSION}") set(_GRPC_GRPCPP gRPC::grpc++) set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>) set(_GRPC_PY_TOOL $<TARGET_FILE:gRPC::grpc_tools::protoc>) # Proto file get_filename_component(hw_proto "helloworld.proto" ABSOLUTE) get_filename_component(hw_proto_path "${hw_proto}" PATH) # Generated sources set(hw_grpc_src_py "${CMAKE_CURRENT_BINARY_DIR}/helloworld_pb2_grpc.py") set(hw_proto_src_py "${CMAKE_CURRENT_BINARY_DIR}/helloworld_pb2.py") set(hw_proto_src_pyi "${CMAKE_CURRENT_BINARY_DIR}/helloworld_pb2.pyi") find_package(PythonInterp REQUIRED) find_package(Python3 REQUIRED) add_custom_command( OUTPUT "${hw_grpc_src_py}" "${hw_proto_src_py}" "${hw_proto_src_pyi}" COMMAND python3 ARGS -m "${_GRPC_PY_TOOL}" -I "${hw_proto_path}" --python_out "${CMAKE_CURRENT_BINARY_DIR}" --pyi_out "${CMAKE_CURRENT_BINARY_DIR}" --grpc_python_out "${CMAKE_CURRENT_BINARY_DIR}" "${hw_proto}" DEPENDS "${hw_proto}")
尝试添加以下自定义目标也无效:
add_custom_target(run ALL DEPENDS "${hw_proto}")
修改add_custom_command的DEPENDS为生成的Python文件后,问题依然存在。
问题分析与修复
你的CMake配置存在以下几个关键问题,逐一修复即可:
1. 错误定义Python gRPC工具调用方式
手动命令是通过python3 -m grpc_tools.protoc调用Python模块,而非直接调用protoc二进制文件。原配置中set(_GRPC_PY_TOOL $<TARGET_FILE:gRPC::grpc_tools::protoc>)完全错误,不需要找这个目标,直接使用grpc_tools.protoc作为模块名即可。
2. add_custom_command参数传递错误
原配置中ARGS -m "${_GRPC_PY_TOOL}"会把protoc二进制路径当作模块名传入,不符合Python模块调用语法,应改为-m grpc_tools.protoc。
3. 自定义目标未正确依赖生成文件
原自定义目标run依赖原始.proto文件,而非add_custom_command生成的Python输出文件,导致CMake无法触发生成命令。需要让自定义目标依赖add_custom_command的OUTPUT列表。
修复后的完整CMake配置
cmake_minimum_required(VERSION 3.15) # Project project(myproj) # Protobuf set(protobuf_MODULE_COMPATIBLE TRUE) find_package(Protobuf CONFIG REQUIRED) message(STATUS "Using protobuf ${protobuf_VERSION}") # gRPC find_package(gRPC CONFIG REQUIRED) message(STATUS "Using gRPC ${gRPC_VERSION}") set(_GRPC_GRPCPP gRPC::grpc++) set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>) # Proto file get_filename_component(hw_proto "helloworld.proto" ABSOLUTE) get_filename_component(hw_proto_path "${hw_proto}" PATH) # Generated sources set(hw_grpc_src_py "${CMAKE_CURRENT_BINARY_DIR}/helloworld_pb2_grpc.py") set(hw_proto_src_py "${CMAKE_CURRENT_BINARY_DIR}/helloworld_pb2.py") set(hw_proto_src_pyi "${CMAKE_CURRENT_BINARY_DIR}/helloworld_pb2.pyi") find_package(Python3 REQUIRED COMPONENTS Interpreter) add_custom_command( OUTPUT "${hw_grpc_src_py}" "${hw_proto_src_py}" "${hw_proto_src_pyi}" COMMAND ${Python3_EXECUTABLE} ARGS -m grpc_tools.protoc -I "${hw_proto_path}" --python_out="${CMAKE_CURRENT_BINARY_DIR}" --pyi_out="${CMAKE_CURRENT_BINARY_DIR}" --grpc_python_out="${CMAKE_CURRENT_BINARY_DIR}" "${hw_proto}" DEPENDS "${hw_proto}" COMMENT "Generating Python gRPC/Protobuf files from ${hw_proto}" ) # 自定义目标依赖生成的文件,ALL关键字会让CMake默认构建这个目标 add_custom_target(gen_python_protos ALL DEPENDS "${hw_grpc_src_py}" "${hw_proto_src_py}" "${hw_proto_src_pyi}" )
额外说明
- 使用
${Python3_EXECUTABLE}替代硬编码的python3,增强跨平台兼容性。 - 在
--python_out等参数后添加等号,和手动命令格式保持一致(CMake也支持空格,但等号更贴近原生protoc语法)。 - 添加
COMMENT参数,构建时可看到生成文件的提示信息,方便调试。
内容的提问来源于stack exchange,提问作者sama
相关产品推荐
相关产品推荐

