14

我在协议缓冲区文件位于子目录中的项目中使用 FindProtobuf 模块。我希望该子目录中的 CMakeLists.txt 文件调用 protoc 来生成 CPP 文件。我的项目文件夹结构是这样的:

cammy/CMakeLists.txt   # Root CMakeLists.txt
cammy/protofiles/test.proto # protofile
cammy/protofiles/CMakeLists.txt

我在 protobuf 文件夹的 CMakeLists.txt 文件中有 include(FindProtobuf)、find_package 调用和对 PROTOBUF_GENERATE_CPP 的调用。

可执行构建步骤位于根 CMakeLists.txt 文件中,我将生成的文件添加到该文件中的目标可执行文件中,即。

add_executable( ${EXEC} ${SRCS} ${PROTO_SRC} ${PROTO_HEADER} )
target_link_libraries( ${EXEC} ${PROTOBUF_LIBRARIES} )

都在根 CMakeLists.txt 中定义

当我运行 cmake 时,它​​不会运行 protoc 来生成源文件,即使我明确地将生成的源代码绑定到可执行文件,从而创建了一个依赖项。

当我将 protofiles 文件夹中 CMakeLists.txt 的所有内容移动到根 CMakeLists.txt 中时,就会编译 proto 文件。

谁能帮我这个?我希望所有协议缓冲区构建内容都放在 protofiles 文件夹中创建的 CMakeLists.txt 文件中。

我还注意到内部 CMakeLists.txt 中生成的变量(如 PROTO_SRC )在打印时在内部文件中定义(即我得到正确生成的 CPP 文件名)但是当我在根文件中打印相同的变量时..它是空的. 就好像我需要将变量“导出”(如果 cmake 中有方法)到根文件夹。

任何帮助将非常感激。

谢谢卡提克

4

1 回答 1

25

我认为FindProtobuf并不是真的要以这种方式使用。从它的文档:

注意:PROTOBUF_GENERATE_CPP宏 & add_executable()oradd_library() 调用只能在同一目录中正常工作。

您正在尝试PROTOBUF_GENERATE_CPP在子目录中使用宏,尽管 CMake 文档并没有明确说明,但子目录为变量引入了新的范围。这意味着在子目录作用域中设置或修改的任何变量都不会影响父作用域中名称相似的变量。因此,PROTO_SRC在您的 protofiles 目录中可用,但在父目录中不可用的原因。

将变量传递到作用域的方法是使用set(... PARENT_SCOPE),所以在 protofiles/CMakeLists.txt 你可以这样做:

PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER test.proto)

set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} PARENT_SCOPE)
set(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARIES} PARENT_SCOPE)
set(PROTO_SRC ${PROTO_SRC} PARENT_SCOPE)
set(PROTO_HEADER ${PROTO_HEADER} PARENT_SCOPE)

但是,这仍然没有让我们一路走好!

CMake 实际上并没有调用 protoc 编译器来生成 .pb.h 和 .pb.cc 文件——它用于add_custom_command执行此操作。自定义命令将 .pb.h 和 .pb.cc 文件指定为输出,并且仅在构建依赖于这些文件的后续目标时才调用自定义命令(即执行 protoc)。

因此,在配置时(当 CMake 执行时)这些文件不存在。如果您尝试将它们作为源添加到add_libraryoradd_executable命令,这是一个问题 - CMake 需要被告知这些文件在运行时不存在,但它们在构建时存在。

这样做的方法是将这些文件的GENERATED属性设置为。TRUE宏会自动执行此PROTOBUF_GENERATE_CPP操作,但与变量一样,该属性不会填充到父范围中。因此,在您的顶级 CMakeLists.txt 中,您还需要添加:

set_source_files_properties(${PROTO_SRC} ${PROTO_HEADER} PROPERTIES
                            GENERATED TRUE)

如您所见,PROTOBUF_GENERATE_CPP在不同的目录中使用对应的add_library/add_executable命令有点脆弱。如果你可以避免这样做,你可能应该这样做。

于 2013-10-13T10:48:33.107 回答