CMake目标依赖来编译protobuf文件

时间:2019-06-18 09:39:35

标签: cmake protocol-buffers

我想用protobuf从某些cmake/make定义中构建一个c ++静态库。
我创建了一个自定义COMMAND,将protobuf编译为c++,并将其设置为对我的静态库的PRE_BUILD依赖项。

project(mylib)

set(PROTO_PATH "${CMAKE_CURRENT_SOURCE_DIR}/proto_definitions")

file(GLOB PROTO_FILES "${PROTO_PATH}/*.proto")
foreach(PROTO_FILE in ${PROTO_FILES})
    string(REGEX REPLACE "[.]proto$" ".pb.cc" OUTPUT_SOURCE ${PROTO_FILE})
    list(APPEND OUTPUT_SOURCES ${OUTPUT_SOURCE}) 
endforeach()

add_custom_command(TARGET ${PROJECT_NAME}
                   PRE_BUILD
                   COMMAND protoc --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/compiled_proto ${PROTO_FILES}
                   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                   COMMENT "some comment")
add_library(${PROJECT_NAME} STATIC ${OUTPUT_SOURCES})

target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})



运行cmake时出现以下错误:
CMake错误:无法确定目标“ mylib”的链接语言

不管出现此错误,都会生成makefile,但是当我制作mylib时,它不会触发任何原型编译

2 个答案:

答案 0 :(得分:2)

CMake更原生的方法是添加带有OUTPUT签名的自定义命令以生成.cc文件,然后将它们用作库的源。这样,他们CMake将知道它们是什么以及如何生产它们:

project(mylib)

set(PROTO_PATH "${CMAKE_CURRENT_SOURCE_DIR}/proto_definitions")

file(GLOB PROTO_FILES "${PROTO_PATH}/*.proto")
foreach(PROTO_FILE in ${PROTO_FILES})
    string(REGEX REPLACE "[.]proto$" ".pb.cc" OUTPUT_SOURCE ${PROTO_FILE})
    list(APPEND OUTPUT_SOURCES ${OUTPUT_SOURCE}) 
endforeach()

add_custom_command(OUTPUT ${OUTPUT_SOURCES}
                   COMMAND protoc --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/compiled_proto ${PROTO_FILES}
                   DEPENDS ${PROTO_FILES}
                   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                   COMMENT "some comment")
add_library(${PROJECT_NAME} STATIC ${OUTPUT_SOURCES})

target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})

这样,将有一个命令读取所有.proto文件并生成所有.cc文件-这意味着,如果.proto文件中的任何一个发生更改,所有.cc个文件将重新生成。我不熟悉Protobuffers,所以我不知道这是否理智。如果它们是独立的,则最好为每个输出文件引入一个add_custom_command

另外,给定要传递给protocc的参数,您可能必须修改OUTPUT_SOURCES中的路径以正确指向生成的文件。

还要注意,CMake带有一个FindProtobuf模块,该模块定义了一个protobuf_generate_cpp()命令,因此您可能想使用它而不是手工编码Protobuf支持。

答案 1 :(得分:0)

评论上面的答案:cmake foreach中没有in,花了我一些时间来解决。

在研究了他的回答后(非常感谢!),我总结了一个对我有用的方法,它有以下特点:

  1. 原始目录和输出目录可以不同
  2. 生成 grpc_output
  3. 为每个原型创建一个 custom_command

我的项目结构是:

  • hwpb/(超级项目库)
    • cpp/
      • hwpb/(存储 *.pb.cc,*.pb.h)
      • CMakeLists.txt
    • proto/(存储原型)
    • go/(以及其他语言,此处未提及)

这是我的 CMakeListx.txt:

set(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../proto")
set(OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/hwpb")

file(GLOB PROTO_FILES "${PROTO_DIR}/*.proto")
foreach(PROTO_FILE ${PROTO_FILES})
    get_filename_component (FILENAME ${PROTO_FILE} NAME_WLE)
    set(PROTO_SRC "${OUTPUT_DIR}/${FILENAME}.pb.cc")
    set(PROTO_HDR "${OUTPUT_DIR}/${FILENAME}.pb.h")
    set(GRPC_SRC "${OUTPUT_DIR}/${FILENAME}.grpc.pb.cc")
    set(GRPC_HDR "${OUTPUT_DIR}/${FILENAME}.grpc.pb.h")

    add_custom_command(
        OUTPUT "${PROTO_SRC}" "${PROTO_HDR}" "${GRPC_SRC}" "${GRPC_HDR}"
        COMMAND ${_PROTOBUF_PROTOC}
        ARGS --plugin=protoc-gen-grpc=${_GRPC_CPP_PLUGIN_EXECUTABLE}
            --cpp_out="${OUTPUT_DIR}" --grpc_out="${OUTPUT_DIR}"
            -I"${PROTO_DIR}" "${PROTO_FILE}"
        DEPENDS ${PROTO_FILE}
    )
    list(APPEND OUTPUT_SOURCES ${PROTO_SRC} ${GRPC_HDR})
endforeach()

add_library(hwpb ${OUTPUT_SOURCES})
target_link_libraries(hwpb ${_GRPC_GRPCPP_UNSECURE} ${_PROTOBUF_LIBPROTOBUF})
target_include_directories(hwpb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})