Введение
Последние пару месяцев я работал над проектом, состоящим из нескольких репозиториев (и со временем их будет все больше и больше). Каждый репозиторий является частью более крупной структуры, где один из репозиториев может зависеть от любого количества других репозиториев. Поскольку все они являются частью одного фреймворка, я бы хотел, чтобы они были COMPONENTS
общего пространства имен CMake. Я также хотел бы, чтобы пользователю нужно было клонировать только те репозитории (и их зависимости), которые его интересуют.
Я новичок в CMake и пытаюсь заставить это работать, включаться и выключаться для последние пару месяцев без особого успеха. Я прочитал и посмотрел несколько разговоров о "Modern CMake" и безуспешно искал разные форумы. Поэтому я надеюсь, что кто-то здесь сможет мне помочь или хотя бы указать мне правильное направление. Любая помощь приветствуется!
Краткий пример
Теперь я представлю краткий пример, чтобы было более понятно, что я ищу.
Представьте, что у нас есть эти репозитории:
- Rep1 не зависит от других репозиториев
- Rep2 зависит от Rep1
- Rep3 зависит от Rep1 и Rep2
- Rep4 зависит от Rep3
- ...
Если пользователя интересует только Rep2. Тогда должно быть возможно только клонировать Rep1 и Rep2.
Для этого я хотел бы иметь возможность сделать это:
- Для Rep2 вызовите
find_package(COMMON_NAMESPACE REQUIRED COMPONENTS Rep1)
, а затем target_link_libraries
- Для Rep3 звоните
find_package(COMMON_NAMESPACE REQUIRED COMPONENTS Rep1 Rep2)
, а затем target_link_libraries
- Для Rep4 звоните
find_package(COMMON_NAMESPACE REQUIRED COMPONENTS Rep3)
, а затем target_link_libraries
Однако я не знаю, как чтобы заставить КОМПОНЕНТЫ работать при наличии разных репозиториев для разных КОМПОНЕНТОВ. Это не альтернатива общему CMakeLists.txt
верхнего уровня, который вызывается add_subdirectory
для каждого репозитория, так как я хочу, чтобы люди могли клонировать каждый репозиторий отдельно, как они хотят. Если кто-то знает, как этого добиться, я был бы очень благодарен, если бы вы могли мне это объяснить!
Что у меня есть сейчас
На данный момент я просто пытаюсь решить эту проблему следующим образом:
- Для Rep2 звоните
find_package(Rep1 REQUIRED)
, а затем target_link_libraries(Rep2 PUBLIC COMMON_NAMESPACE::Rep1)
- Для Rep3 звоните
find_package(Rep1 REQUIRED)
, find_package(Rep2 REQUIRED)
и затем target_link_libraries(Rep3 PUBLIC COMMON_NAMESPACE::Rep1 COMMON_NAMESPACE::Rep2)
- Для Rep4 звоните
find_package(Rep3 REQUIRED)
а затем target_link_libraries(Rep4 PUBLIC COMMON_NAMESPACE::Rep3)
Первые два работают. Но с третьим я получаю:
Target "Rep4" links to target "COMMON_NAMESPACE::Rep1" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
Как это можно решить без вызова find_package(Rep1 REQUIRED)
и find_package(Rep2 REQUIRED)
в Rep4?
Текущая структура файла
Вот набросок файловой структуры. «Пример» - это общее пространство имен, которое я хотел бы использовать:
- Rep1
- cmake
- Rep1_ProjectConfig.cmake.in
- включить
- src
- CMakeLists.txt
- some_ cpp. cpp
- CMakeLists.txt
- Rep2
- cmake
- Rep2_ProjectConfig.cmake.in
- включить
- src
- CMakeLists.txt
- some_ cpp. cpp
- CMakeLists.txt
- Rep3
- cmake
- Rep3_ProjectConfig.cmake. в
- включить
- SRC
- CMakeLists.txt
- some_ cpp. cpp
- CMakeLists.txt
- Rep4
- cmake
- Rep4_ProjectConfig.cmake.in
- включить
- src
- CMakeLists.txt
- some_ cpp. cpp
- CMakeLists.txt
- ...
Текущее содержимое файла CMake
Файл CMakeLists.txt
верхнего уровня для каждого репозитория выглядит следующим образом:
cmake_minimum_required(VERSION 3.9)
project(RepX_Project
VERSION 1.0
DESCRIPTION "RepX_Project ..."
LANGUAGES CXX
)
add_subdirectory(src)
Файл CMakeLists.txt
, расположенный в src
для каждого репозитория, выглядит так:
# The namespace used
set(NS Example)
set(HEADER_LIST
"${PROJECT_SOURCE_DIR}/include/${NS}/RepX/some_header.h"
...
)
set(SRC_LIST
some_cpp.cpp
...
)
# Some of them might depend on one (or more) of the other repositories
find_package(RepY REQUIRED)
...
add_library(RepX SHARED ${SRC_LIST} ${HEADER_LIST})
add_library(${NS}::RepX ALIAS RepX)
set_target_properties(RepX
PROPERTIES
VERSION ${RepX_Project_VERSION}
SOVERSION ${RepX_Project_SOVERSION}
CXX_STANDARD 17
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)
target_include_directories(RepX
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
)
# If this repository depends on one (or more) of the other repositories
target_link_libraries(RepX
PUBLIC
${NS}::RepY
...
)
target_compile_features(RepX PUBLIC cxx_std_17)
source_group(TREE "${PROJECT_SOURCE_DIR}/include" PREFIX "Header Files" FILES ${HEADER_LIST})
include(CMakePackageConfigHelpers)
configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${PACKAGE_VERSION}
COMPATIBILITY SameMajorVersion
)
install(TARGETS RepX
EXPORT RepXTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
install(EXPORT RepXTargets
FILE
RepXTargets.cmake
NAMESPACE
${NS}::
DESTINATION
lib/cmake/${PROJECT_NAME}
)
install(FILES
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION
lib/cmake/${PROJECT_NAME}
)
install(DIRECTORY
${PROJECT_SOURCE_DIR}/include/
DESTINATION
include
)
Файл .cmake.in
для каждого репозитория выглядит следующим образом:
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/RepXTargets.cmake")
check_required_components("RepX")
Вопросы
- Как использовать
COMPONENTS
, когда разные компоненты находятся в собственном репозитории? - Что мне нужно исправить, чтобы
find_package
мог рекурсивно находить все мои зависимости? - Как правильно обрабатывать пространства имен CMake?
- В настоящее время мне нужно создать папку COMMON_NAMESPACE в каждом подключаемом каталоге для каждого репозитория. Кроме того, в
.cmake.in
мне нужно жестко указать целевое имя для каждой библиотеки в каждом репозитории, чтобы это работало.
- Правильный ли мой
.cmake.in
файл? Должен ли я также создавать свой собственный файл конфигурации CMake? - Могу ли я улучшить
CMakeLists.txt
файлы, расположенные в каталогах src
?
Последнее примечание
I очень признателен, что вы нашли время прочитать это и (надеюсь) помогли мне с этим. Извините, что этот пост такой длинный, я постарался быть как можно более кратким и в то же время показать все, что у меня есть, чтобы вы могли получить полную картину. Просто спросите, есть ли какая-либо другая информация, которая вам нужна, чтобы лучше / легче помочь с этим, я рад предоставить любую дополнительную информацию, которая может вам понадобиться! Надеюсь, это поможет и другим людям.
Спасибо и хорошего дня!