#[=======================================================================[.rst: myx_add_library --------------- Вспомогательная функция для создания библиотеки:: myx_add_library(NAME TYPE [ OUTPUT_NAME output_name ] | [ EXPORT_FILE_NAME file_name ] | [ EXPORT_BASE_NAME base_name ]) Обязательные параметры: `NAME` - имя библиотеки и `TYPE` - тип цели. Параметр `OUTPUT_NAME` определяет базовое имя выходных файлов. Параметр `EXPORT_FILE_NAME` задаёт имя заголовочного файла экспортируемых переменных, а `EXPORT_BASE_NAME` - базовый суффикс для формирования имён переменных. Все остальные параметры передаются в стандартную функцию `add_library()` #]=======================================================================] include_guard(GLOBAL) include(CMakePackageConfigHelpers) include(GenerateExportHeader) if(${CMAKE_VERSION} VERSION_LESS "3.17.0") set(MYX_CMAKE_LIB_DIR_BACKPORT "${CMAKE_CURRENT_LIST_DIR}") endif() function(myx_add_library NAME TYPE) if(${CMAKE_VERSION} VERSION_LESS "3.17.0") set(CMAKE_CURRENT_FUNCTION_LIST_DIR ${MYX_CMAKE_LIB_DIR_BACKPORT}) endif() set(options) set(oneValueArgs OUTPUT_NAME EXPORT_FILE_NAME EXPORT_BASE_NAME) set(multiValueArgs) cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT ARG_OUTPUT_NAME) set(ARG_OUTPUT_NAME ${NAME}) endif() # Вызов стандартной функции `add_library()` add_library(${NAME} ${TYPE} ${ARG_UNPARSED_ARGUMENTS}) if(TYPE STREQUAL "INTERFACE") # Библиотека, состоящая только из заголовочных файлов не требует сборки. # Стандартные пути к заголовочным файлам target_include_directories(${NAME} SYSTEM INTERFACE $) else() string(TOUPPER ${NAME} PROJECT_NAME_UPPER) # Опция для разрешения сборки динамической библиотеки cmake_dependent_option(${PROJECT_NAME_UPPER}_BUILD_SHARED "Build shared library for ${NAME}" ON "BUILD_SHARED_LIBS" OFF) # Опция для разрешения сборки статической библиотеки cmake_dependent_option(${PROJECT_NAME_UPPER}_BUILD_STATIC "Build static library for ${NAME}" ON "NOT BUILD_SHARED_LIBS" OFF) # Стандартные пути к заголовочным файлам target_include_directories(${NAME} PUBLIC $ PRIVATE $ $ ) # Сборка позиционно-независимых объектных файлов нужна # для создания динамической библиотеки set_target_properties(${NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) if(NOT EXPORT_BASE_NAME) string(TOUPPER ${NAME} ARG_EXPORT_BASE_NAME) endif() if(NOT ARG_EXPORT_FILE_NAME) set(ARG_EXPORT_FILE_NAME "${PROJECT_SOURCE_DIR}/include/${NAME}/${NAME}_export.hpp") endif() generate_export_header(${NAME} BASE_NAME ${ARG_EXPORT_BASE_NAME} EXPORT_MACRO_NAME "EXPORT_${ARG_EXPORT_BASE_NAME}" DEPRECATED_MACRO_NAME "DEPRECATED_${ARG_EXPORT_BASE_NAME}" NO_DEPRECATED_MACRO_NAME "NO_DEPRECATED_${ARG_EXPORT_BASE_NAME}" NO_EXPORT_MACRO_NAME "NO_EXPORT_${ARG_EXPORT_BASE_NAME}" STATIC_DEFINE "STATIC_DEFINE_${ARG_EXPORT_BASE_NAME}" EXPORT_FILE_NAME ${ARG_EXPORT_FILE_NAME} DEFINE_NO_DEPRECATED ) set_property(TARGET ${NAME} APPEND PROPERTY INTERFACE_HEADER_FILES "${ARG_EXPORT_FILE_NAME}") # Цель для создания динамической библиотеки из объектных файлов if(${PROJECT_NAME_UPPER}_BUILD_SHARED) # Для создания динамической библиотеки используются объектные файлы цели ${NAME} add_library(${NAME}_shared SHARED $) # Установка дополнительных свойств для цели ${NAME}_shared # VERSION: версия библиотеки # SOVERSION: мажорная версия библиотеки # LIBRARY_OUTPUT_DIRECTORY: каталог для записи результатов сборки # OUTPUT_NAME: базовое имя выходного файла (без учёта расширения) set_target_properties(${NAME}_shared PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} OUTPUT_NAME ${ARG_OUTPUT_NAME}) endif() # Цель для создания статической библиотеки из объектных файлов if(${PROJECT_NAME_UPPER}_BUILD_STATIC) # Для создания статической библиотеки используются объектные файлы цели ${NAME} add_library(${NAME}_static STATIC $) # Установка дополнительных свойств для цели ${NAME}_static # ARCHIVE_OUTPUT_DIRECTORY: каталог для записи результатов сборки # OUTPUT_NAME: базовое имя выходного файла (без учёта расширения) set_target_properties(${NAME}_static PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} OUTPUT_NAME ${ARG_OUTPUT_NAME}) endif() endif() # Если вызов был выполнен не из проекта верхнего уровня, # то созданная цель исключается из цели `all`. # При этом сама цель `${NAME}` может участвовать в сборке, # если окажется в перечне зависимостей. if(NOT PROJECT_IS_TOP_LEVEL) set_target_properties(${NAME} PROPERTIES EXCLUDE_FROM_ALL True) return() endif() # Правила для установки библиотек и относящихся к ним файлов. # Если вызов был выполнен не из проекта верхнего уровня, # то эти правила не обрабатываются. write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/${NAME}ConfigVersion.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) configure_package_config_file( ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/library-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${NAME}Config.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${NAME} NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) install(EXPORT ${NAME}Targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${NAME} COMPONENT dev ) install( FILES ${PROJECT_BINARY_DIR}/${NAME}ConfigVersion.cmake ${PROJECT_BINARY_DIR}/${NAME}Config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${NAME} COMPONENT dev ) # Формирование файла для pkg-config file(WRITE "${PROJECT_BINARY_DIR}/${NAME}.pc" "prefix=${CMAKE_INSTALL_PREFIX}\n" "exec_prefix=${CMAKE_INSTALL_PREFIX}\n" "includedir=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}\n") if(NOT TYPE STREQUAL "INTERFACE") file(APPEND "${PROJECT_BINARY_DIR}/${NAME}.pc" "libdir=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}\n") endif() file(APPEND "${PROJECT_BINARY_DIR}/${NAME}.pc" "\n" "Name: ${NAME}\n" "Description: ${NAME} library\n" "Version: ${PROJECT_VERSION}\n" "\n" "Requires:\n" "Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}\n") if(NOT TYPE STREQUAL "INTERFACE") file(APPEND "${PROJECT_BINARY_DIR}/${NAME}.pc" "Libs: -L${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} -l${NAME}\n") endif() # Установка файла для pkg-config install( FILES "${PROJECT_BINARY_DIR}/${NAME}.pc" COMPONENT dev DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") if(TYPE STREQUAL "OBJECT") # Установка динамической библиотеки if(TARGET ${NAME}_shared) install( TARGETS ${NAME}_shared EXPORT ${NAME}Targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib ) endif() if(TARGET ${NAME}_static) # Установка статической библиотеки install( TARGETS ${NAME}_static EXPORT ${NAME}Targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT static ) endif() endif() if(TYPE STREQUAL "INTERFACE") # Установка библиотеки из заголовочных файлов target_include_directories(${NAME} SYSTEM INTERFACE $) install( TARGETS ${NAME} EXPORT ${NAME}Targets COMPONENT lib ) endif() endfunction()