CMake中为库目标生成protobuf文件的依赖配置问题求解
问题根因说明
- 最初配置失败的原因:你将生成的
${LIB_HEADERS}放到了protocol目标的PUBLIC源文件中,CMake在配置阶段处理app目标的依赖时,会尝试查找这些对外暴露的头文件,但这些文件是构建阶段才会生成的,配置阶段不存在就会报错,将其移到PRIVATE是正确的操作。 - 后续编译找不到头文件的原因:
protocol目标对外暴露的包含路径是${CMAKE_CURRENT_BINARY_DIR},即构建目录下的protocol子目录,生成的msg.pb.h直接放在这个目录下,没有protocol/前缀,所以你写#include "protocol/msg.pb.h"自然找不到。
具体解决方法
解法1:修改包含语句(最简单)
直接把main.cpp中的包含语句改成:
#include "msg.pb.h"
因为protocol目标已经通过target_include_directories将${CMAKE_CURRENT_BINARY_DIR}(存放生成头文件的目录)设为PUBLIC属性,app链接protocol后会自动继承这个包含路径,直接能找到msg.pb.h。
解法2:调整包含路径适配现有include写法
如果你要保留#include "protocol/msg.pb.h"的写法,修改protocol目录的CMakeLists.txt中的target_include_directories配置,把${CMAKE_CURRENT_BINARY_DIR}换成${CMAKE_BINARY_DIR}(项目全局构建根目录):
target_include_directories(protocol PUBLIC . ${CMAKE_BINARY_DIR} # 替换原来的${CMAKE_CURRENT_BINARY_DIR} ${Protobuf_INCLUDE_DIRS} )
因为生成的msg.pb.h路径是<全局构建目录>/protocol/msg.pb.h,将全局构建目录加入包含路径后,就能匹配protocol/msg.pb.h的查找逻辑。
额外优化:彻底解决生成顺序问题
为了彻底避免app编译时protobuf头文件还未生成的问题,有两个可选优化:
- 显式标记生成文件属性,在
protocol目录的CMakeLists.txt中protobuf_generate_cpp调用后加一行:
set_source_files_properties(${LIB_SOURCES} ${LIB_HEADERS} PROPERTIES GENERATED TRUE)
- 显式声明依赖,在
app目录的CMakeLists.txt中加一行:
add_dependencies(app protocol)
更推荐的现代化写法
直接用新版Protobuf模块提供的protobuf_generate的TARGET参数,自动处理所有生成、源文件添加、依赖逻辑,不需要手动管理生成的源文件,protocol目录的CMakeLists.txt可以简化为:
add_library(protocol) find_package(Protobuf REQUIRED) protobuf_generate( TARGET protocol LANGUAGE cpp PROTO_FILES msg.proto ) target_include_directories(protocol PUBLIC . ${CMAKE_CURRENT_BINARY_DIR} # 按需换成${CMAKE_BINARY_DIR} ${Protobuf_INCLUDE_DIRS} ) target_link_libraries(protocol PUBLIC ${Protobuf_LIBRARIES})
这种写法兼容性更好,不会出现依赖顺序或者源文件属性不对的问题。
内容的提问来源于stack exchange,提问作者Dávid Tóth
相关产品推荐
相关产品推荐

