CMake: какой смысл искать пакет() если вам все равно нужно указать путь к модулю CMAKE?


Я пытаюсь получить систему сборки кросс-plattform, работающую с использованием CMake. Теперь программное обеспечение имеет несколько зависимостей. Я сам их скомпилировал и установил в своей системе.

некоторые примеры файлов, которые были установлены:

-- Installing: /usr/local/share/SomeLib/SomeDir/somefile
-- Installing: /usr/local/share/SomeLib/SomeDir/someotherfile
-- Installing: /usr/local/lib/SomeLib/somesharedlibrary
-- Installing: /usr/local/lib/SomeLib/cmake/FindSomeLib.cmake
-- Installing: /usr/local/lib/SomeLib/cmake/HelperFile.cmake

теперь CMake имеет find_package() открывающий Find*.cmake файл и ищет библиотеки в системе и определяет некоторые переменные, такие как SomeLib_FOUND etc.

Мои CMakeLists.txt содержит что-то вроде это:

set(CMAKE_MODULE_PATH "/usr/local/lib/SomeLib/cmake/;${CMAKE_MODULE_PATH}")
find_package(SomeLib REQUIRED)

первая команда определяет, где CMake ищет после Find*.cmake и я добавил каталог SomeLib здесь FindSomeLib.cmake, так что find_package() строительство как и ожидалось.

но это немного странно, потому что одна из причин, почему find_package() существует, чтобы уйти от не-кросс-plattform жестко закодированных путей.

как это обычно делается? Я должен скопировать

4 100

4 ответа:

команда find_package имеет два режима: Module режим и Config режим. Ты пытаешься ... используйте Module режим, когда вам действительно нужно Config режим.

режим модуль

расположенном внутри ваш проект. Что-то вроде этого:

CMakeLists.txt
cmake/FindFoo.cmake
cmake/FindBoo.cmake

CMakeLists.txt содержание:

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
find_package(Foo REQUIRED) # FOO_INCLUDE_DIR, FOO_LIBRARIES
find_package(Boo REQUIRED) # BOO_INCLUDE_DIR, BOO_LIBRARIES

include_directories("${FOO_INCLUDE_DIR}")
include_directories("${BOO_INCLUDE_DIR}")
add_executable(Bar Bar.hpp Bar.cpp)
target_link_libraries(Bar ${FOO_LIBRARIES} ${BOO_LIBRARIES})

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

режим настройки (установить)

расположенном за пределами и произведен install команда другого проекта (Foo например).

foo библиотека:

> cat CMakeLists.txt 
cmake_minimum_required(VERSION 2.8)
project(Foo)

add_library(foo Foo.hpp Foo.cpp)
install(FILES Foo.hpp DESTINATION include)
install(TARGETS foo DESTINATION lib)
install(FILES FooConfig.cmake DESTINATION lib/cmake/Foo)

упрощенная версия файла config:

> cat FooConfig.cmake 
add_library(foo STATIC IMPORTED)
find_library(FOO_LIBRARY_PATH foo HINTS "${CMAKE_CURRENT_LIST_DIR}/../../")
set_target_properties(foo PROPERTIES IMPORTED_LOCATION "${FOO_LIBRARY_PATH}")

по умолчанию проект установлен в :

> cmake -H. -B_builds
> cmake --build _builds --target install
-- Install configuration: ""
-- Installing: /usr/local/include/Foo.hpp
-- Installing: /usr/local/lib/libfoo.a
-- Installing: /usr/local/lib/cmake/Foo/FooConfig.cmake

режим настройки (использовать)

использовать find_package(... CONFIG) включить FooConfig.cmake с импортированной цели foo:

> cat CMakeLists.txt 
cmake_minimum_required(VERSION 2.8)
project(Boo)

# import library target `foo`
find_package(Foo CONFIG REQUIRED)

add_executable(boo Boo.cpp Boo.hpp)
target_link_libraries(boo foo)
> cmake -H. -B_builds -DCMAKE_VERBOSE_MAKEFILE=ON
> cmake --build _builds
Linking CXX executable Boo
/usr/bin/c++ ... -o Boo /usr/local/lib/libfoo.a

обратите внимание, что импортируемые цель очень настраиваемые. Смотрите мой ответ.

обновление

как это обычно делается? Я должен скопировать cmake/ каталог SomeLib в мой проект и установить CMAKE_MODULE_PATH относительно?

Если вы не доверяете CMake иметь этот модуль, то -да, делать это. Вот что я делаю в качестве запасного варианта.

отметим, что FindFoo.cmake модули каждый вид моста между платформ-зависимостью и платформ-независимостью-они смотрят в различных платформ-специфических местах для того чтобы получить пути внутри переменные, имена которых не зависят от платформы.

не нужно для указания пути модуля как такового. CMake поставляется со своим собственным набором встроенных скриптов find_package, и их расположение находится в пути CMAKE_MODULE_PATH по умолчанию.

более нормальным вариантом использования для зависимых проектов, которые были CMakeified, было бы использовать команду External_project CMake, а затем включить Use[Project].файл cmake из подпроекта. Если вам просто нужно найти[проект].cmake скрипт, скопируйте его из подпроекта и в свой собственный исходный код проекта, и тогда вам не нужно будет увеличивать CMAKE_MODULE_PATH для того, чтобы найти подпроект на системном уровне.

если вы используете cmake для создания SomeLib себя (скажем, как часть superbuild), рассмотреть возможность использования Реестр Пакетов Пользователей. Это не требует жестко закодированных путей и является кросс-платформенным. В Windows (включая mingw64) он работает через реестр. Если вы изучите, как список префиксов установки строится с помощью CONFIG режим find_packages () команда, вы увидите, что реестр пакетов пользователей является одним из элементы.

краткое how-to

связать цели SomeLib что вам нужно вне этого внешнего проекта, добавив их в набор экспорта в CMakeLists.txt файлы, в которых они создаются:

add_library(thingInSomeLib ...)
install(TARGETS thingInSomeLib Export SomeLib-export DESTINATION lib)

создать на SomeLib в своем ${CMAKE_CURRENT_BUILD_DIR} и сохраните это место в реестре пакетов пользователей, добавив два вызова в export () до CMakeLists.txt связанные с SomeLib:

export(EXPORT SomeLib-export NAMESPACE SomeLib:: FILE SomeLibConfig.cmake) # Create SomeLibConfig.cmake
export(PACKAGE SomeLib)                                                    # Store location of SomeLibConfig.cmake

ваш вопрос find_package(SomeLib REQUIRED) commmand в CMakeLists.txt файл проекта, который зависит от SomeLib без" не кросс-платформенных жестко закодированных путей " возиться с CMAKE_MODULE_PATH.

когда это может быть правильный подход

этот подход, вероятно, лучше всего подходит для ситуаций, когда вы никогда не будете использовать свое программное обеспечение ниже каталога сборки (например, вы перекрестно компилируете и никогда ничего не устанавливаете на свой машина, или вы создаете программное обеспечение только для запуска тестов в каталоге сборки), так как он создает ссылку на a .файл cmake в вашем выводе "build", который может быть временным.

но если вы никогда не устанавливаете SomeLib в вашем рабочем процессе, вызов EXPORT(PACKAGE <name>) позволяет избежать жесткого пути. И, конечно же, если вы устанавливаете SomeLib, вы, наверное, знаете свои платформы, CMAKE_MODULE_PATH и т. д., Так что отличный ответ @user2288008 будет у вас покрыт.