如何避免CMake中Protobuf生成文件的不必要重编译?
解决Protobuf/GRPC文件重复生成问题
你当前使用add_custom_target的方式会导致每次构建都重新生成文件,原因是该目标没有关联输出文件,CMake无法判断是否需要重新执行。正确的做法是使用add_custom_command关联输入输出文件,让CMake通过文件时间戳自动判断是否需要重新生成。
具体实现步骤
定义所有生成的输出文件
先遍历你的proto文件列表,明确每个文件会生成的C++输出文件(包括pb、grpc.pb以及mock文件):# 遍历proto文件,生成对应的输出文件路径 foreach(proto_file ${those_proto_files}) get_filename_component(proto_name ${proto_file} NAME_WE) list(APPEND proto_generated_files ${the_output_dir}/${proto_name}.pb.h ${the_output_dir}/${proto_name}.pb.cc ${the_output_dir}/${proto_name}.grpc.pb.h ${the_output_dir}/${proto_name}.grpc.pb.cc ${the_output_dir}/mock_${proto_name}.h ) endforeach()用add_custom_command生成文件
使用add_custom_command关联输入(proto文件、protoc和grpc插件目标)和输出文件,CMake会自动检查文件更新情况:add_custom_command( OUTPUT ${proto_generated_files} COMMAND $<TARGET_FILE:${proto_target}> --grpc_out=generate_mock_code=true:${the_output_dir} --cpp_out=${the_output_dir} --plugin=protoc-gen-grpc=$<TARGET_FILE:${grpc_cpp_plugin_target}> -I ${that_dir} ${those_proto_files} DEPENDS ${those_proto_files} ${proto_target} ${grpc_cpp_plugin_target} COMMENT "Generating C++ code from Protobuf/GRPC files" )关联到依赖目标
你可以直接让业务目标依赖生成的文件,或者创建一个聚合目标来管理:# 方式1:直接让业务目标依赖生成的文件 add_dependencies(${that_dependent_target_name} ${proto_generated_files}) # 方式2:创建聚合目标,方便手动触发生成 add_custom_target(ThatThing ALL DEPENDS ${proto_generated_files}) add_dependencies(${that_dependent_target_name} ThatThing)
为什么之前的方法无法生效
add_custom_target本身没有输出文件,CMake会默认每次构建都执行该目标的命令。execute_process在CMake配置阶段运行,而$<TARGET_FILE>是生成阶段的表达式,配置阶段还未确定目标的最终路径,因此无法识别。LOCATION属性已被CMake废弃,禁止直接读取目标路径,必须使用$<TARGET_FILE>这类生成表达式。find_program用于在系统中查找已安装的程序,无法识别CMake目标或生成表达式。
注意事项
- 确保所有生成的输出文件都被列在
OUTPUT参数中,否则CMake可能漏检部分文件导致重复生成。 - 如果proto文件存在导入关系,要确保
-I参数包含所有依赖的proto文件目录。 - 当proto文件修改、protoc或grpc_cpp_plugin更新时,CMake会自动重新生成文件,这是合理的更新逻辑,无需避免。
内容的提问来源于stack exchange,提问作者Ghasem Ramezani
相关产品推荐
相关产品推荐

