CMake несколько библиотек в разных репозиториях - PullRequest
0 голосов
/ 14 июля 2020

Введение

Последние пару месяцев я работал над проектом, состоящим из нескольких репозиториев (и со временем их будет все больше и больше). Каждый репозиторий является частью более крупной структуры, где один из репозиториев может зависеть от любого количества других репозиториев. Поскольку все они являются частью одного фреймворка, я бы хотел, чтобы они были COMPONENTS общего пространства имен CMake. Я также хотел бы, чтобы пользователю нужно было клонировать только те репозитории (и их зависимости), которые его интересуют.

Я новичок в CMake и пытаюсь заставить это работать, включаться и выключаться для последние пару месяцев без особого успеха. Я прочитал и посмотрел несколько разговоров о "Modern CMake" и безуспешно искал разные форумы. Поэтому я надеюсь, что кто-то здесь сможет мне помочь или хотя бы указать мне правильное направление. Любая помощь приветствуется!

Краткий пример

Теперь я представлю краткий пример, чтобы было более понятно, что я ищу.

Представьте, что у нас есть эти репозитории:

  1. Rep1 не зависит от других репозиториев
  2. Rep2 зависит от Rep1
  3. Rep3 зависит от Rep1 и Rep2
  4. Rep4 зависит от Rep3
  5. ...

Если пользователя интересует только 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 для каждого репозитория, так как я хочу, чтобы люди могли клонировать каждый репозиторий отдельно, как они хотят. Если кто-то знает, как этого добиться, я был бы очень благодарен, если бы вы могли мне это объяснить!

Что у меня есть сейчас

На данный момент я просто пытаюсь решить эту проблему следующим образом:

  1. Для Rep2 звоните find_package(Rep1 REQUIRED), а затем target_link_libraries(Rep2 PUBLIC COMMON_NAMESPACE::Rep1)
  2. Для Rep3 звоните find_package(Rep1 REQUIRED), find_package(Rep2 REQUIRED) и затем target_link_libraries(Rep3 PUBLIC COMMON_NAMESPACE::Rep1 COMMON_NAMESPACE::Rep2)
  3. Для 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
    • включить
      • Пример
        • Rep1
          • some_header.h
    • src
      • CMakeLists.txt
      • some_ cpp. cpp
    • CMakeLists.txt
  • Rep2
    • cmake
      • Rep2_ProjectConfig.cmake.in
    • включить
      • Пример
        • Rep2
          • some_header.h
    • src
      • CMakeLists.txt
      • some_ cpp. cpp
    • CMakeLists.txt
  • Rep3
    • cmake
      • Rep3_ProjectConfig.cmake. в
    • включить
      • Пример
        • Rep3
          • some_header.h
    • SRC
      • CMakeLists.txt
      • some_ cpp. cpp
    • CMakeLists.txt
  • Rep4
    • cmake
      • Rep4_ProjectConfig.cmake.in
    • включить
      • Пример
        • Rep4
          • some_header.h
    • 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")

Вопросы

  1. Как использовать COMPONENTS, когда разные компоненты находятся в собственном репозитории?
  2. Что мне нужно исправить, чтобы find_package мог рекурсивно находить все мои зависимости?
  3. Как правильно обрабатывать пространства имен CMake?
    • В настоящее время мне нужно создать папку COMMON_NAMESPACE в каждом подключаемом каталоге для каждого репозитория. Кроме того, в .cmake.in мне нужно жестко указать целевое имя для каждой библиотеки в каждом репозитории, чтобы это работало.
  4. Правильный ли мой .cmake.in файл? Должен ли я также создавать свой собственный файл конфигурации CMake?
  5. Могу ли я улучшить CMakeLists.txt файлы, расположенные в каталогах src?

Последнее примечание

I очень признателен, что вы нашли время прочитать это и (надеюсь) помогли мне с этим. Извините, что этот пост такой длинный, я постарался быть как можно более кратким и в то же время показать все, что у меня есть, чтобы вы могли получить полную картину. Просто спросите, есть ли какая-либо другая информация, которая вам нужна, чтобы лучше / легче помочь с этим, я рад предоставить любую дополнительную информацию, которая может вам понадобиться! Надеюсь, это поможет и другим людям.

Спасибо и хорошего дня!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...