【问题标题】:CMake protobuf external to application code应用程序代码外部的 CMake protobuf
【发布时间】:2020-08-09 20:10:06
【问题描述】:

基本上,我想要这样的结构:

MainRepo
    +---app1
    +---app2
    +---common
        +---some_lib1
        +---some_lib2
        +---protobuf
                +---comms.proto
                +---cs
                    +---Comms.pb.cs
                +---cpp
                    +---comms.pb.cc
                    +---comms.pb.h

我希望能够查看 repo 并拥有一个脚本,该脚本为 repo 中的应用程序运行所有不同语言的 protoc。这是一个包含两个不同 arm 机器和一个 x64 的应用程序的单声道存储库。我基本上是在运行 protoc,它会为 c、js、cs、cpp 等生成所有源文件,并将它们放在 protobuf 下的它们自己的文件夹中。

例如,我想要 app1,去查找 c++ 标头和源代码并使用它们来构建应用程序。目前,我一直在破解的示例使用 cmake 生成 .cc 和 .h 这对我来说很不方便,因为 intellisense 抱怨说,因为这些文件在我写作时不存在。

无论如何,我整天都在破解 cmake。我总是以 cmake 的前向声明错误而告终,并且无法编译我的 .cc 和 .h

PROJECT(test)

CMAKE_MINIMUM_REQUIRED (VERSION 2.6)

SET(CMAKE_CXX_FLAGS "-g -Wall -Werror -std=c++11")

ADD_EXECUTABLE(main main.cpp)

TARGET_LINK_LIBRARIES(main proto ${PROTOBUF_LIBRARY})

find_package(Protobuf REQUIRED)

set(PROTOBUF_IMPORT_DIRS "../proto")
set (msgs ${PROTOBUF_IMPORT_DIRS}/communications.proto)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${msgs})
add_library(proto SHARED ${PROTO_SRCS})
target_link_libraries(proto ${PROTOBUF_LIBRARY})

想知道是否有任何建议。我不想将我的 protobuf 东西放在我的公共文件夹之外,我也不需要 protoc 来生成这些文件,因为我用另一种方式(尽管我可以改变这种方式)。我只是想确保语言特定的文件仍然可以查看,而不仅仅是在 cmake 期间生成的,我无法查看它们。

【问题讨论】:

    标签: cmake protocol-buffers external


    【解决方案1】:

    我的 2 美分,

    这就是我为 google/or-tools 所做的 参考:https://github.com/google/or-tools

    Protobuf 集成

    我正在使用Fetchcontent()(CMake >= 3.18 具有 SOURCE_SUBDIR 选项 IIRC),但我还需要对其进行修补(例如具有 CMP0077) 你可以在这里找到 protobuf 补丁:https://github.com/google/or-tools/blob/stable/patches/protobuf-v3.12.2.patch

    cmake/dependencies/CMakeLists.txt

    include(FetchContent)
    set(BUILD_SHARED_LIBS OFF)
    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
    set(BUILD_TESTING OFF)
    
    message(CHECK_START "Fetching Protobuf")
    list(APPEND CMAKE_MESSAGE_INDENT "  ")
    set(protobuf_BUILD_TESTS OFF)
    set(protobuf_BUILD_EXPORT OFF)
    set(protobuf_MSVC_STATIC_RUNTIME OFF)
    # FetchContent_Declare(SOURCE_SUBDIR) was introduced in 3.18
    FetchContent_Declare(
      protobuf
      GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
      GIT_TAG "v3.12.2"
      PATCH_COMMAND git apply "${CMAKE_CURRENT_LIST_DIR}/../../patches/protobuf-v3.12.2.patch"
      SOURCE_SUBDIR cmake)
    FetchContent_MakeAvailable(protobuf)
    list(POP_BACK CMAKE_MESSAGE_INDENT)
    message(CHECK_PASS "fetched")
    

    参考:https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/dependencies/CMakeLists.txt#L142-L168

    注意:对于 cmake ExternalProject + execute_process() 见:https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/utils.cmake#L66-L137

    生成 Protobuf 文件

    由于我们已经集成了 Protobuf,现在我们可以访问 protobuf::protoc。 要构建 proto 文件,只需适应

    # Get Protobuf include dirs
    get_target_property(protobuf_dirs protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES)
    foreach(dir IN LISTS protobuf_dirs)
      if ("${dir}" MATCHES "BUILD_INTERFACE")
        message(STATUS "Adding proto path: ${dir}")
        list(APPEND PROTO_DIRS "--proto_path=${dir}")
      endif()
    endforeach()
    
    # Generate Protobuf cpp sources
    set(PROTO_HDRS)
    set(PROTO_SRCS)
    file(GLOB_RECURSE proto_files RELATIVE ${PROJECT_SOURCE_DIR}
      "common/protobuf/*.proto"
      )
    
    foreach(PROTO_FILE IN LISTS proto_files)
      #message(STATUS "protoc proto(cc): ${PROTO_FILE}")
      get_filename_component(PROTO_DIR ${PROTO_FILE} DIRECTORY)
      get_filename_component(PROTO_NAME ${PROTO_FILE} NAME_WE)
      set(PROTO_HDR ${PROJECT_BINARY_DIR}/${PROTO_DIR}/${PROTO_NAME}.pb.h)
      set(PROTO_SRC ${PROJECT_BINARY_DIR}/${PROTO_DIR}/${PROTO_NAME}.pb.cc)
      #message(STATUS "protoc hdr: ${PROTO_HDR}")
      #message(STATUS "protoc src: ${PROTO_SRC}")
      add_custom_command(
        OUTPUT ${PROTO_SRC} ${PROTO_HDR}
        COMMAND protobuf::protoc
        "--proto_path=${PROJECT_SOURCE_DIR}"
        ${PROTO_DIRS}
        "--cpp_out=${PROJECT_BINARY_DIR}"
        ${PROTO_FILE}
        DEPENDS ${PROTO_FILE} protobuf::protoc
        COMMENT "Generate C++ protocol buffer for ${PROTO_FILE}"
        VERBATIM)
      list(APPEND PROTO_HDRS ${PROTO_HDR})
      list(APPEND PROTO_SRCS ${PROTO_SRC})
    endforeach()
    

    参考:https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/cpp.cmake#L234-L279

    在您可以使用 PROTO_HDRPROTO_SRC 之后,例如将它们添加到您的目标来源等...

    注意:对于 .Net,您可以查看 https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/dotnet.cmake#L30-L60

    总而言之,只要适应您的需要,例如在源代码树中生成而不是二进制目录等,你应该能够做任何你想做的事情......

    【讨论】:

    • 我试过你的 cmake 流程。我仍然得到 AuxillaryParseTableField google::protobuf::internal 没有命名类型。这仍然是我拥有 cmake 文件的方式的前向声明问题吗?
    • 这一切都奏效了。显然,在 12.3 中使用辅助修复了一个错字,这导致我在追逐 cmake 问题时走错了路。您的流程效果很好。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    • 2021-05-27
    相关资源
    最近更新 更多