Как использовать "современные" экспортированные цели CMake в контексте существующих библиотек
Я обновляю (очень старый) модуль поиска библиотеки. Таким образом, ситуация представляет собой существующую разделяемую библиотеку, которая использует сам CMake. Пользователи могут уже установить это где-нибудь, в репозитории или как угодно.
Теперь они хотят использовать это. Хороший способ был бы
find_package(Foo REQUIRED)
target_link_libraries(MyProject Foo::Foo)
Так вот и цель.
Вопрос в том, как будет выглядеть хороший find_package-Config или -Module, который позволит работать этому 2-х линейному модулю? Он должен соответствовать этим 2 требованиям:
- Разрешить версии CMake использовать библиотеку старше той, которая использовалась для ее создания
- Обеспечить, например, режим C++11. В Find-Module можно установить требование C++11 в зависимости от версии (
cxx_std_11
(CMake 3.8+),cxx_alias_templates
(CMake 3.1+),check_cxx_source_compiles
с кодом C++11 и предупреждением для старых CMakes)
Есть 2 способа сделать это:
- Обновите модуль поиска для определения импортированной библиотеки
Foo::Foo
и настроить его правильно (используя свойства) и было бы неплохо также установитьFOO_INCLUDE_DIR
а такжеFOO_LIBRARIES
для старых CMake без целей.
Это довольно просто: просто используйтеfind_path
а такжеfind_library
, установите импортированную цель и все готово. Работает с прямой и обратной совместимостью, поэтому можно найти даже старые версии.
Использование:
Пользовательские копии (самые свежие) FindFoo.cmake
к его проекту, например, в cmake/Modules
и очки CMAKE_MODULE_PATH
к нему или скопировать FindFoo.cmake
к некоторому пути CMake по умолчанию.
Слушая Дэниела Пфайффера и Modern CMake, который говорит
If you are the library author, don't make a Find<mypackage>.cmake script!
Поэтому мы экспортируем и устанавливаем цели.
Это немного грязно. Требуются следующие изменения:- добавлять
EXPORTS FooTargets
а такжеINCLUDES DESTINATION include
вinstall(TARGETS
(см. Pfeiffer #24), который в основном просто определяет экспорт. (Я действительно не понимаю, почему я хотел бы создать дополнительное имя для того, что уже имеет имя. Почему приведенная ниже команда не может просто ссылаться на цель?) - добавлять
install(EXPORT FooTargets NAMESPACE Foo:: DESTINATION lib/cmake/Foo)
который бы создалFooTargets.cmake
в<CMAKE_INSTALL_PREFIX>/lib/cmake/Foo
который определяет цельFoo::Foo
(надеюсь) со всеми его зависимостями - Добавить "что-то" создание
FooConfigVersion.cmake
возможно с помощьюwrite_basic_package_version_file
что, насколько я понимаю, жестко кодирует версию этого файла - Создать
FooConfig.cmake
которые могут использоватьfind_dependency
искать библиотеки, от которых зависит FooFooTargets.cmake
- устанавливать
FooConfig.cmake
а такжеFooConfigVersion.cmake
вlib/cmake/Foo
- модифицировать
target_include_directories
использовать отдельныйBUILD_INTERFACE
а такжеINSTALL_INTERFACE
пути
- добавлять
Использование:find_package
автоматически находит FooConfig.cmake
а также FooConfigVersion.cmake
когда Foo
ищется.
Поэтому модуль Config должен быть предпочтительным, но я вижу следующие проблемы:
- Процесс выглядит сложнее
- Его нельзя использовать, чтобы позволить пользователям находить более старые версии библиотеки (которые не использовали этот подход)
- Он исключает всех (библиотечных) пользователей со старым CMake (2.8.11, вероятно, является минимально необходимым здесь)
- Для сборки самой библиотеки требуется более новая версия CMake.
- Требование C++11 кажется очень сложным для кодирования
Так можем ли мы решить требования с помощью CMake-Config? Ответ должен дать решение или, по крайней мере, обоснованное "невозможно". Следует также решить проблемы, изложенные в конце.
Последнее замечание: я думаю, что это хорошая запись вики, если она не существует.