首页 > 解决方案 > CMake如何收集自动生成的源文件和头文件

问题描述

首先介绍一下上下文,我试图解耦一个包含 protobuf 定义以及使用 proto 的实体的 repo。我想创建一个仅包含 protobuf 定义和脚本的存储库,这些定义和脚本以不同的语言导出生成的类,以便由使用它们的其他项目导入。

在 c++ 中生成 protobuf 类实际上非常简单(几行 python 脚本),但之后就变得棘手了。您最终会得到一组杂乱无章的源文件。我想使用 CMake 收集所有文件并生成库。文件结构应如下所示:

/root
    /proto-package-1
        foo.pb.h
        foo.pb.cc
    /proto-package-2
        /proto-package-3
            bar.pb.h
            bar.pb.cc
        bazz.pb.h
        bazz.pb.cc

我在 CMake 中有点菜鸟,但我读过在 CMakeLists.txt 文件中明确列出所有源文件是一种很好的做法。但我想让这个 c++ 库的生成完全自动化。这是违反此规则的充分理由吗?什么 CMake 命令可以帮助我?

cmake_minimum_required (VERSION 3.5)

project ("CMakeProject1")
set(TARGET_NAME CMakeProject1)

# Include sub-projects.
include_directories(${CMAKE_SOURCE_DIR})

add_library(${TARGET_NAME} STATIC 
${CMAKE_SOURCE_DIR}/root/proto-package-1/foo.pb.h
${CMAKE_SOURCE_DIR}/root/proto-package-1/foo.pb.cc
//This is not going to cut it. Cannot add a proto and auto-generate.
)

标签: c++cmakeprotocol-buffers

解决方案


您还可以在 cmake 中生成它们并创建生成文件的列表

# Get list of .proto files
file(GLOB_RECURSE proto_files RELATIVE ${PROJECT_SOURCE_DIR} "*.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)
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()

# [optional] Create a library of all generated C++ files
add_library(${PROJECT_NAME}_proto ${PROTO_SRCS} ${PROTO_HDRS})
set_target_properties(${PROJECT_NAME}_proto PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${PROJECT_NAME}_proto PROPERTIES CXX_STANDARD 11)
set_target_properties(${PROJECT_NAME}_proto PROPERTIES CXX_STANDARD_REQUIRED ON)
set_target_properties(${PROJECT_NAME}_proto PROPERTIES CXX_EXTENSIONS OFF)
target_include_directories(${PROJECT_NAME}_proto PRIVATE
  ${PROJECT_SOURCE_DIR}
  ${PROJECT_BINARY_DIR}
  $<TARGET_PROPERTY:protobuf::libprotobuf,INTERFACE_INCLUDE_DIRECTORIES>
  )
target_link_libraries(${PROJECT_NAME}_proto PRIVATE protobuf::libprotobuf)

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


推荐阅读