Как использовать библиотеки в моем проекте CMake, которые необходимо установить в первую очередь?
у меня проблема с моей системой сборки CMake. Есть CMakeLists.txt
файлы, определяющие время выполнения или библиотеки или использующие ExternalProjects_Add()
для загрузки и создания внешнего кода. Из-за зависимостей эти проекты должны находить друг друга. Теперь я хочу иметь CMakeLists.txt
на верхнем уровне, который строит все эти сразу. Для того, чтобы найти проект, должен быть установлен is. Но поиск проектов уже выполняется во время настройки в CMake.
repository
├─project
│ ├─game (Depends on engine, uses EngineConfig.cmake once installed)
│ │ ├─CMakeLists.txt
│ │ ├─include
│ │ ├─src
│ │ └─textures
│ ├─engine (Depends on boost, uses built-in FindBoost.cmake)
│ │ ├─CMakeLists.txt
│ │ ├─include
│ │ └─src
│ ├─boost (Not the source code, just an ExternalProject_Add call)
│ : └─CMakeLists.txt
│
├─build
│ ├─game
│ ├─engine
│ ├─boost (Source will be downloaded and built here)
│ : ├─download
│ ├─source
│ :
│
├─install
│ ├─game
│ │ ├─bin
│ │ └─textures
│ ├─engine
│ │ ├─include
│ │ │ └─engine
│ │ │ ├─EngineConfig.cmake (Needed to find the library)
│ │ │ :
│ │ │
│ │ └─lib
│ ├─boost (Layout is up to the external library)
│ : └─ ...
│
└─CMakeLists.txt (Calls add_subdirectory for all inside the project folder)
запустите процесс CMake для каждого проект: используя execute_process(${CMAKE_COMMAND} ...)
, Я могу настроить и построить каждый проект на настроить время. Однако это означает, что я всегда должен запускать CMake после редактирования кода и не могу скомпилировать из среды IDE, для которой я создал файлы проекта.
связывание с целями CMake: запуск процесса CMake для всех внешних библиотек в порядке, так как я не работаю над ними. Мои собственные библиотеки можно использовать, вызвав target_link_libraries()
С их имена. Однако, связывая не достаточно. Мои библиотеки включают каталоги внешних библиотек. Они также должны быть доступны для проекта using.
как я могу использовать библиотеки в моем проекте CMake, которые необходимо установить в первую очередь?
3 ответов
вы можете классифицировать свои проекты на три группы:
- внешние зависимости, вы не работаете в этом супер-проекте
- проекты, над которыми вы работаете, но слишком сложны, чтобы добавить их в подкаталог, например, имеющие слишком много целей или по другим причинам. (У вас, похоже, нет такого проекта в вашем примере.)
- проекты, над которыми вы работаете: они будут добавлены в качестве подкаталога супер-проект.
перед настройкой супер-проекта необходимо настроить, построить и установить проект в группах #1 и #2:
- вы можете сделать это перед запуском супер-проекта
CMakeLists.txt
, например, из shell-скрипта - или, как вы упомянули, из супер-проекта
CMakeLists.txt
, используяexecute_process(${CMAKE_COMMAND} ...)
. Вы можете сделать это условно, используя результат соответствующий .
вам нужно решите, если проекты в группе #3, как engine
будет использоваться только в проектах, которые используют их в качестве подкаталогов или вы собираетесь использовать их как автономные библиотеки, встроенные в свои собственные деревья сборки.
кроме того, вы упомянули, что: "мои библиотеки включают каталоги внешних библиотек". Давайте рассмотрим все такие возможные библиотеки engine
может зависеть от:
- сказать,
LIB1
иLIB2
частные и общественные внешние зависимостиengine
и их конфигурационные модули экспортируют старую школуLIB1_*
иLIB2_*
переменные -
LIB3
иLIB4
являются частными и публичными внешними зависимостямиengine
и их конфигурационные модули экспортируютLIB3
иLIB4
импортные библиотеки
под публичными и частными зависимостями я имею в виду, используется ли конкретная библиотека или не используется на интерфейсе engine
.
теперь, если engine
используется только в качестве подкаталог, то соответствующий раздел engine/CMakeLists.txt
- это:
add_library(engine ...)
target_include_directories(engine
PRIVATE
${LIB1_INCLUDE_DIRS}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
${LIB2_INCLUDE_DIRS})
target_compiled_definitions(engine
PRIVATE ${LIB1_DEFINITIONS}
PUBLIC ${LIB2_DEFINITIONS})
target_link_libraries(engine
PRIVATE LIB3
PUBLIC LIB4)
на repository/CMakeLists.txt
:
add_subdirectory(engine)
add_subdirectory(game)
на game/CMakeLists.txt
:
add_executable(game ...)
target_link_libraries(game engine)
include dirs как двигателя, так и его общедоступных зависимостей будут правильно перенаправлены в game
.
если engine
также будет построен в собственном дереве сборки (в другом проекте), вам нужно добавить код экспорта в engine/CMakeLists.txt
и, возможно, пользовательский config-модуль, который вызывает find_package
(или find_dependency
) для свои зависимости. См.как использовать CMake для поиска и ссылки на библиотеку с помощью install-export и find_package? для сведения. Одна из проблем, не обсуждаемых в этом ответе, - это поиск зависимостей библиотеки в модуле конфигурации библиотеки:
ссылочный ответ SO просто устанавливает <lib>-targets.cmake
скрипт, сгенерированный install(EXPORT ...)
команда, как config-module:
install(EXPORT engine-targets
FILE engine-config.cmake
DESTINATION lib/cmake/engine)
это решение хорошо, когда engine
не имеет дополнительных зависимостей. Если это так, они должны быть найдены в начале модуля config, который должен быть написан вручную.
engine/engine-config.cmake:
include(CMakeFindDependencyMacro)
find_dependency(some-dep-of-engine)
include(${CMAKE_CURRENT_LIST_DIR}/engine-targets.cmake)
и engine/CMakeLists.txt
:
install(EXPORT engine-targets
FILE engine-targets.cmake
DESTINATION lib/cmake/engine)
install(FILES engine-config.cmake
DESTINATION lib/cmake/engine)
Примечание:CMakeFindDependencyMacro
был представлен в CMake 3.0. С более старым CMake вы можете использовать find_package
вместо find_dependency
(обработка тихих и необходимых параметров не будет перенаправлена в зависимость).
при экспорте библиотеки из engine
project вам нужно указать его каталоги включения. Код ниже-это упрощение примера, приведенного в http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#creating-packages. Пути adjasted для установки префикса install/engine
для сборки и установки
спасибо @Tsyvarev и @tamas.кенез!--9--> вы за два хороших ответа. Я закончил тем, что использовал супер-строить шаблон. Проект верхнего уровня не делает много во время настройки. Во время сборки он запускает внешние процессы CMake для настройки, сборки и установки проектов.
обычно это реализуется с помощью ExternalProject_Add()
вместо add_subdirectory()
для добавления проектов. Я нашел add_custom_command()
работать лучше, так как он не выполняет дополнительных задач в фон, как создание файлов штампов и так далее.
# add_project(<project> [DEPENDS project...])
function(add_project PROJECT)
cmake_parse_arguments(PARAM "" "" "DEPENDS" ${ARGN})
add_custom_target(${PROJECT} ALL DEPENDS ${PARAM_DEPENDS})
# Paths for this project
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT})
set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT})
set(INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT})
# Configure
escape_list(CMAKE_MODULE_PATH)
escape_list(CMAKE_PREFIX_PATH)
add_custom_command(TARGET ${TARGET}
COMMAND ${CMAKE_COMMAND}
--no-warn-unused-cli
"-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH_ESCAPED}"
"-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH_ESCAPED}"
-DCMAKE_BINARY_DIR=${BUILD_DIR}
-DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
${SOURCE_DIR}
WORKING_DIRECTORY ${BUILD_DIR})
# Build
add_custom_command(TARGET ${TARGET}
COMMAND ${CMAKE_COMMAND}
--build .
--target install
WORKING_DIRECTORY ${BUILD_DIR})
# Help later find_package() calls
append_global(CMAKE_PREFIX_PATH ${INSTALL_DIR})
endfunction()
вот две вспомогательные функции. Мне потребовалось довольно много времени, чтобы выяснить правильный способ передачи параметров списка другим процессам CMake без их интерпретации и передачи Как нескольких параметров.
# escape_list(<list-name>)
function(escape_list LIST_NAME)
string(REPLACE ";" "\;" ${LIST_NAME}_ESCAPED "${${LIST_NAME}}")
set(${LIST_NAME}_ESCAPED "${${LIST_NAME}_ESCAPED}" PARENT_SCOPE)
endfunction()
# append_global(<name> value...)
function(append_global NAME)
set(COMBINED "${${NAME}}" "${ARGN}")
list(REMOVE_DUPLICATES COMBINED)
set(${NAME} "${COMBINED}" CACHE INTERNAL "" FORCE)
endfunction()
единственным недостатком является то, что каждый проект должен иметь цель установки для этого. Поэтому вам нужно добавить фиктивную команду установки, такую как install(CODE "")
для проектов, у которых нет команды install в противном случае, например, те, кто просто звонит ExternalProject_Add
.