#c #cmake #protocol-buffers
#c #cmake #протокол-буферы
Вопрос:
Чтобы сначала немного прояснить контекст, я пытаюсь отделить репозиторий, который включает определения protobuf, а также объекты, использующие прототипы. Я хочу создать репозиторий только с определениями protobuf и сценариями, которые экспортируют результирующие классы на разных языках для импорта другими проектами, которые их используют.
Генерация классов protobuf на c на самом деле довольно проста (несколько строк скрипта 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.
)
Комментарии:
2. Вопросы: Нравится ли, поддерживается ли и используется ли этот модуль CMake? Компилирует ли он файлы .proto, а также назначает ли их целевым объектам? И если да, то как я могу указать, какую версию протокола использовать?
3. Последнее обновление было десять дней назад. Существует (к сожалению, недокументированный) режим, в котором он проверяет источники целевого объекта и добавляет правила для добавления файлов, сгенерированных протоколом, к целевому объекту. Что касается версии протокола, вы можете попробовать передать требуемую версию команде find_package .
4. Я постараюсь заставить это работать (что является проблемой в Windows). Похоже, что это действительно было сделано с идеей включить определения proto в одно и то же репозиторий, в отличие от того, что я пытаюсь
Ответ №1:
Вы также можете сгенерировать их в 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
Ответ №2:
Я полагаю, что вы можете использовать внутреннюю функцию пакета FindProtobuf для создания статических библиотек, содержащих реализации protobuf:
find_package(Protobuf 3.12 REQUIRED)
add_library(protopackage1 STATIC proto-package-1/foo.proto)
protobuf_generate(LANGUAGE cpp TARGET protopackage1)
Вы можете передать дополнительные аргументы protobuf_generate
, но вам нужно будет выяснить, как protobuf_generate_cpp передает их.
Комментарии:
1. Это может быть функция, которую я искал. Очень удобно, что они включили его с четкой документацией о том, как его использовать.
2. Вы всегда можете поднять вопрос об этом или даже отправить исправление документа; возможно, они просто еще не рассмотрели ваш вариант использования. Как говорится: «патчи приветствуются»