使用Google Protocol Buffers的CMake

25

我正在尝试使用 CMake 和 Protocol Buffers 来构建我的小项目。

根目录下有许多子目录,包含很多库和可执行文件。我的第一想法是将 .proto 文件放在一个子目录中,但当我阅读了 这个答案 后,我将其改为了库。但是当我试图在我的可执行文件中包含消息头时,却找不到它。

错误信息:

fatal error: msgs.pb.h: No such file or directory
 #include "msgs.pb.h"
                     ^
compilation terminated.

我是通过创建一个名为 "build" 的目录,然后从其中运行 "cmake .. && make" 命令来运行它。

我已经查看了一下,似乎生成的文件会被放在 build/messages 目录中,因此我可以使用 include_directories(build/messages) 但这似乎不是...合适的。对于 protobuf,有没有更好的方法来处理这种情况呢?我想将消息文件放在它们自己的文件夹中的原因是它们将在许多不同的小可执行文件中使用。

如果有关于改进我的 CMake 结构的其他一般提示,也将不胜感激 :)

目录:

root
   messages
   core
   server

根目录/CMakeLists.txt:

project(lillebror)
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0015 NEW)

set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost COMPONENTS date_time log thread system)
find_package(Protobuf REQUIRED)
if(Boost_FOUND)
    add_definitions(-std=c++11)
    add_subdirectory(messages)
    add_subdirectory(core)
    add_subdirectory(server)
    add_subdirectory(testserver)
endif()

消息/CMakeLists.txt:

file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles})
add_library(messages STATIC ${ProtoSources} ${ProtoHeaders})
target_link_libraries(messages ${Boost_LIBRARIES} ${PROTOBUF_LIBRARY})

核心/CMakeLists.txt:

aux_source_directory(src SRC_LIST)
add_library(core STATIC ${SRC_LIST})
target_link_libraries(core messages ${Boost_LIBRARIES})

服务器/CMakeLists.txt:

aux_source_directory(src SRC_LIST)
include_directories(../messages) <---- I thought this would sove my problem
include_directories(../core/src)
link_directories(../core/build)
add_executable(server ${SRC_LIST})
target_link_libraries(server core ${Boost_LIBRARIES})

服务器主文件/main.cpp:

#include "msgs.pb.h"
int main()
{
    return 0;
}

请查看:https://medium.com/3yourmind/generate-grpc-source-files-using-cmake-ec3acd246b45 - Gelldur
1个回答

31
我认为这里的问题在于PROTOBUF_GENERATE_CPP函数设置了.pb.h和.pb.cc文件存在于构建树中,而不是源代码树中。 虽然这是个好的做法(避免污染源代码树),但它意味着你的调用include_directories(../messages)向搜索路径添加了错误的值。它添加的是源目录"root/messages",而你需要的是"[build root]/messages"。 你可能只需要用以下内容替换该行:
include_directories(${CMAKE_BINARY_DIR}/messages)

然而,一种更加强壮、可维护的方式可能是在 messages/CMakeLists.txt 文件中设置所需的包含路径。为了将这个值暴露给父级作用域,需要使用 set(... PARENT_SCOPE) 或者:

set(ProtobufIncludePath ${CMAKE_CURRENT_BINARY_DIR}
    CACHE INTERNAL "Path to generated protobuf files.")

然后在顶层的CMakeLists.txt文件中,您可以这样做:

include_directories(${ProtobufIncludePath})

如果您的 messages 库本身需要 #include 生成的 protobuf 文件(这是正常情况),那么它也应该有类似的 include_directories 调用。

话虽如此,如果您可以将 CMake v2.8.12 指定为最低版本,则可以改用 target_include_directories 命令。

在 messages/CMakeLists.txt 中的 add_library 调用之后,您只需执行以下操作:

target_include_directories(messages PUBLIC ${CMAKE_CURRENT_BINARY_DIR})

那么,任何依赖于 messages 的其他目标都会自动添加适当的“messages”包含目录到其自身 - 您根本不需要显式调用include_directories


看起来Ubuntu稳定版正在运行2.8.11,所以我选择了稍微长一点的版本。 - dutt
我还应该提到:不需要调用link_directories(它自己的文档不鼓励使用),并且正如你可能知道的那样,如果编译器是GCC或Clang,add_definitions(-std=c++11)可能只适用于它。除此之外,整个结构看起来都很好。 - Fraser
啊,那我尝试移除 link_directories 调用。我在这个小项目中使用 gcc,所以这个定义是没问题的,不过还是谢谢你提醒我 :) - dutt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接