Мне дается несколько проектов (git-репозитории), и каждый из них зависит от ряда библиотек (также git-репозиториев). Каждый проект имеет только один целевой исполняемый файл и связывает библиотеки из других репозиториев.
Моя файловая структура:
├── libraries
│ ├── libraryX (git:master)
│ │ ├── build
│ │ │ └── libX.so
│ │ ├── CMakeLists.txt
│ │ ├── fileX.cpp
│ │ └── fileX.h
│ ├── libraryY (git:master)
│ │ ├── build
│ │ │ └── libY.so
│ │ ├── CMakeLists.txt
│ │ ├── fileY.cpp
│ │ └── fileY.h
│ └── libraryZ (git:master)
│ ├── build
│ │ └── libZ.so
│ ├── CMakeLists.txt
│ ├── fileZ.cpp
│ └── fileZ.h
└── projects
├── projectA (git:master)
│ ├── build
│ │ └── outA
│ ├── CMakeLists.txt
│ └── mainA.cpp
└── projectB (git:master)
├── build
│ └── outB
├── CMakeLists.txt
└── mainB.cpp
Это пример CMakeLists.txt
файла внутри libraryX
:
cmake_minimum_required(VERSION 3.6)
project(libraryX LANGUAGES CXX)
set(libraries $ENV{LIBRARIES})
set(projects $ENV{PROJECTS})
add_library(libX SHARED fileX.cpp)
target_include_directories(libX PUBLIC ${libraries}/libraryX/)
В настоящее время я создаю каждую библиотеку вручную, которая генерирует файлы *.so
, а затем я перехожу к проекту и собираю исполняемый файл. Это пример CMakeLists.txt
изнутри projectA
:
cmake_minimum_required(VERSION 3.6)
project(projectA LANGUAGES CXX)
set(libraries $ENV{LIBRARIES})
set(projects $ENV{PROJECTS})
add_executable(outA mainA.cpp)
target_include_directories(outA
PUBLIC
${libraries}/libraryX/
${libraries}/libraryY/
${libraries}/libraryZ/
${projects}/projectA/
)
target_link_libraries(outA
${libraries}/libraryX/build/libX.so
${libraries}/libraryY/build/libY.so
${libraries}/libraryZ/build/libZ.so
)
Меня интересует сборка/запуск только одного проекта (например, projectA/
) за раз, но я не хочу вручную прекомпилировать каждую библиотеку каждый раз, когда вношу изменения.
Также я не могу перемещать libraries/
под проект (например, projectA/libraries/libraryX
), потому что projectB/
тоже зависит от них, и мне не нравится иметь два клона одного и того же репозитория на одном компьютере в родственных папках. Я также не могу изменять и переупорядочивать содержимое репозиториев под себя, потому что над ними работают разные команды и планируют выпустить их в виде полных пакетов, устанавливаемых из apt-get в будущем. Наконец, я не хочу использовать один верхний уровень CMakeLists.txt
внутри рабочей области, потому что проекты A и B независимы друг от друга.
Я пытался изучить add_subdirectory
и target_sources
, но не мог понять, как настроить таргетинг на источник, если я хочу, чтобы одна и та же библиотека использовалась разными исполняемыми файлами в projectA
и projectB
.
Конечно, я могу запустить скрипт bash, который собирает cmake в каждой библиотеке, но я думал, что это работа CMake, чтобы делать такие вещи. Я явно не вижу здесь какого-то очевидного решения.
Может ли кто-нибудь помочь мне заставить CMake предварительно скомпилировать библиотеку, прежде чем связывать их с целью?
Спасибо!
P.S. Как я могу указать CMake компилировать файлы *.dll
вместо *.so
и *.exe
вместо двоичных файлов Linux?
Я читал и смотрел множество руководств и читал много ответов stackoverflow об архитектуре проектов CMake. Я попытался запустить проект в Visual Studio в Windows в надежде, что он сам разберется, но на самом деле это не помогло. Я написал bash-скрипт, который компилирует библиотеки перед их связыванием, но это кажется неправильным, потому что мне обещали, что CMake действительно сделает это за меня. Я также пытался использовать систему подкаталогов, как упоминалось в другом ответе stackoverflow, но на самом деле это не удалось.
@ViniciusAlmada, когда я нацеливаюсь на источник из подкаталога, я должен назвать источник, но источником может быть либо projectA/outA
, либо projectB/outB
. Итак, всякий раз, когда я использую libraryX
из projectA
, мне приходится редактировать CMakeFiles и наоборот. Или можно назвать оба исполняемых файла как out
Я думаю, вам нужно настроить репозиторий пакетов, например, например. Конан
Ваш libraryX/CMakeLists.txt
будет выглядеть так:
cmake_minimum_required(VERSION 3.6)
project(libraryX LANGUAGES CXX)
add_library(libX SHARED fileX.cpp)
target_include_directories(
libX
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
В корневом каталоге всех подпроектов вы можете добавить CMakeLists.txt
, который выполняет add_subdirectory()
для всех библиотек (сначала) и двоичных файлов (последних).
Затем в projectX/CMakeLists.txt
просто укажите нужные вам цели CMake:
cmake_minimum_required(VERSION 3.6)
project(projectX LANGUAGES CXX)
add_executable(outA mainA.cpp)
target_include_directories(
outA
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
# NOTE No need for any other paths
)
target_link_libraries(
outA
PRIVATE
libX
libY
libZ
)
Обновление (после того, как я заметил, что это отдельные репозитории git):
Вам нужно экспортировать цели вашей библиотеки (создать и установить их в один и тот же префикс) и использовать find_package(libX)
в projectX/CMakeLists.txt
, чтобы найти цель для связи с ней.
Хорошо иметь отдельные библиотеки (по сравнению с монорепозиторием;).
Спасибо! Простое добавление подкаталогов без каких-либо изменений в библиотеках сработало для меня. Теперь, когда я создаю проект A, он также создает все добавленные библиотеки!
Я думаю, что вашу проблему можно решить с помощью
add_subdirectory
, но вы уже пытались. Можете ли вы поделиться более подробной информацией о том, что происходит, когда вы используете эту команду?