Вопрос или проблема
В моем проекте есть смесь зависимостей, некоторые из которых имеют файлы cmake, которые я могу использовать с помощью target_link_libraries()
(например, boost_program_options
), а некоторые — нет (например, openssl
; мне нужно скомпилировать собственную версию по причинам совместимости), и для них я вынужден использовать ExternalProject_Add
, а затем мне нужно использовать смесь target_link_libraries()
, target_compile_options()
и target_link_options()
, например:
# Это только для определенных библиотек.
target_compile_options(my_program
PUBLIC
-I${OPENSSL_INSTALL_DIR}/include
)
# Это только для определенных библиотек.
target_link_options(my_program
PUBLIC
-L${OPENSSL_INSTALL_DIR}/lib
)
# Это касается всего, но я должен помнить,
# добавляю ли я имя цели или фактические файлы библиотек.
target_link_libraries(my_program
PUBLIC
boost_program_options
libssl.a libcrypto.a
)
Что я хотел бы сделать, так это заменить это на что-то вроде:
# Все в одном месте.
target_link_libraries(my_program
PUBLIC
boost_program_options
openssl_pseudo_target
)
И в другом месте сделать так, чтобы openssl_pseudo_target
сообщал cmake
о соответствующих опциях компиляции/ссылки/библиотек, которые следует использовать.
Есть ли способ сделать это или достичь аналогичного эффекта?
Для этого предназначены интерфейсные библиотеки. Они также предоставляют пример, похожий на то, что вы хотите сделать:
Другим случаем использования является применение совершенно целевого подхода к требованиям использования:
add_library(pic_on INTERFACE) set_property(TARGET pic_on PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON) add_library(pic_off INTERFACE) set_property(TARGET pic_off PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE OFF) add_library(enable_rtti INTERFACE) target_compile_options(enable_rtti INTERFACE $<$<OR:$<COMPILER_ID:GNU>,$<COMPILER_ID:Clang>>:-rtti> ) add_executable(exe1 exe1.cpp) target_link_libraries(exe1 pic_on enable_rtti)
Таким образом, спецификация сборки exe1 выражается полностью через связанные цели, и сложность компилятор-специфичных флагов инкапсулирована в INTERFACE библиотечной цели.
П.С. Также есть find_package(OpenSSL)
, который предоставляет необходимые цели, так что вам не нужно создавать свои собственные.
Ответ или решение
Вам действительно можно создать "псевдо-таргет" в CMake для упрощения управления зависимостями, такими как OpenSSL. Для этого идеально подходят интерфейсные библиотеки (INTERFACE libraries), которые позволяют организовать и скрыть сложные зависимости в одном месте. Давайте рассмотрим, как это можно сделать.
Шаги по созданию псевдо-таргета для OpenSSL:
-
Создайте интерфейсную библиотеку для OpenSSL:
Сначала определите интерфейсную библиотеку, которая будет хранить необходимые параметры компиляции и ссылки для OpenSSL. Например:
add_library(openssl_pseudo_target INTERFACE) # Установите параметры компиляции для целевой библиотеки target_compile_options(openssl_pseudo_target INTERFACE -I${OPENSSL_INSTALL_DIR}/include ) # Установите параметры линковки для целевой библиотеки target_link_options(openssl_pseudo_target INTERFACE -L${OPENSSL_INSTALL_DIR}/lib ) # Установите зависимости для линковки target_link_libraries(openssl_pseudo_target INTERFACE libssl.a libcrypto.a )
-
Используйте созданную библиотеку в вашем проекте:
Теперь, когда у вас есть интерфейсная библиотека
openssl_pseudo_target
, вы можете легко использовать ее в других шарах вашего проекта:add_executable(my_program main.cpp) target_link_libraries(my_program PUBLIC boost_program_options openssl_pseudo_target )
Преимущества данного подхода:
- Упрощение управления зависимостями: Вы централизуете все параметры компиляции и линковки для OpenSSL в одном месте, что упрощает поддержку и понимание кода.
- Меньше ошибок: Вам не нужно каждый раз помнить о необходимости указания различных флагов и библиотек для OpenSSL.
- Гибкость: Если в будущем вам потребуется изменить версии или параметры, это можно сделать в одном месте, не затрагивая другие части проекта.
Альтернативный вариант:
Если вы используете pre-packaged версии OpenSSL, стоит рассмотреть возможность использования find_package(OpenSSL)
, что позволит вам избежать ручной настройки. Это обеспечит подключение уже настроенных таргетов OpenSSL:
find_package(OpenSSL REQUIRED)
add_executable(my_program main.cpp)
target_link_libraries(my_program
PUBLIC
boost_program_options
OpenSSL::SSL
OpenSSL::Crypto
)
Таким образом, использование интерфейсных библиотек в сочетании с find_package
предоставляет мощные инструменты для управления зависимостями в Вашем CMake проекте, что значительно упрощает процесс разработки.