myx/MyxCMake/lib/AddLibrary.cmake
2022-10-09 21:14:12 +03:00

227 lines
9.7 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#[=======================================================================[.rst:
myx_add_library
---------------
Вспомогательная функция для создания библиотеки::
myx_add_library(TARGET_NAME TARGET_TYPE
[ OUTPUT_NAME output_name ] |
[ EXPORT_FILE_NAME file_name ] |
[ EXPORT_BASE_NAME base_name ])
Обязательные параметры: `TARGET_NAME` - имя библиотеки и `TARGET_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 TARGET_NAME TARGET_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 ${TARGET_NAME})
endif()
# Вызов стандартной функции `add_library()`
add_library(${TARGET_NAME} ${TARGET_TYPE} ${ARG_UNPARSED_ARGUMENTS})
if(TARGET_TYPE STREQUAL "INTERFACE")
# Библиотека, состоящая только из заголовочных файлов не требует сборки.
# Стандартные пути к заголовочным файлам
target_include_directories(${TARGET_NAME} INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
else()
string(TOUPPER ${TARGET_NAME} __project_name_upper)
# Опция для разрешения сборки динамической библиотеки
cmake_dependent_option(${__project_name_upper}_BUILD_SHARED
"Build shared library for ${TARGET_NAME}" ON "BUILD_SHARED_LIBS" OFF)
# Опция для разрешения сборки статической библиотеки
cmake_dependent_option(${__project_name_upper}_BUILD_STATIC
"Build static library for ${TARGET_NAME}" ON "NOT BUILD_SHARED_LIBS" OFF)
# Стандартные пути к заголовочным файлам
target_include_directories(${TARGET_NAME}
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
PRIVATE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# Сборка позиционно-независимых объектных файлов нужна
# для создания динамической библиотеки
set_target_properties(${TARGET_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
if(NOT EXPORT_BASE_NAME)
set(ARG_EXPORT_BASE_NAME ${__project_name_upper})
endif()
if(NOT ARG_EXPORT_FILE_NAME)
set(ARG_EXPORT_FILE_NAME
"${PROJECT_SOURCE_DIR}/include/${TARGET_NAME}/${TARGET_NAME}_export.hpp")
endif()
generate_export_header(${TARGET_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 ${TARGET_NAME} APPEND PROPERTY
INTERFACE_HEADER_FILES "${ARG_EXPORT_FILE_NAME}")
# Цель для создания динамической библиотеки из объектных файлов
if(${__project_name_upper}_BUILD_SHARED)
# Для создания динамической библиотеки используются объектные файлы цели ${TARGET_NAME}
add_library(${TARGET_NAME}_shared SHARED $<TARGET_OBJECTS:${TARGET_NAME}>)
# Установка дополнительных свойств для цели ${TARGET_NAME}_shared
# VERSION: версия библиотеки
# SOVERSION: мажорная версия библиотеки
# LIBRARY_OUTPUT_DIRECTORY: каталог для записи результатов сборки
# OUTPUT_NAME: базовое имя выходного файла (без учёта расширения)
set_target_properties(${TARGET_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)
# Для создания статической библиотеки используются
# объектные файлы цели ${TARGET_NAME}
add_library(${TARGET_NAME}_static STATIC $<TARGET_OBJECTS:${TARGET_NAME}>)
# Установка дополнительных свойств для цели ${TARGET_NAME}_static
# ARCHIVE_OUTPUT_DIRECTORY: каталог для записи результатов сборки
# OUTPUT_NAME: базовое имя выходного файла (без учёта расширения)
set_target_properties(${TARGET_NAME}_static PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}
OUTPUT_NAME ${ARG_OUTPUT_NAME})
endif()
endif()
# Если вызов был выполнен не из проекта верхнего уровня,
# то созданная цель исключается из цели `all`.
# При этом сама цель `${TARGET_NAME}` может участвовать в сборке,
# если окажется в перечне зависимостей.
if(NOT PROJECT_IS_TOP_LEVEL)
set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL True)
return()
endif()
# Правила для установки библиотек и относящихся к ним файлов.
# Если вызов был выполнен не из проекта верхнего уровня,
# то эти правила не обрабатываются.
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${TARGET_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}/${TARGET_NAME}Config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${TARGET_NAME}
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
install(EXPORT ${TARGET_NAME}Targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${TARGET_NAME}
COMPONENT DEV
)
install(
FILES
${PROJECT_BINARY_DIR}/${TARGET_NAME}ConfigVersion.cmake
${PROJECT_BINARY_DIR}/${TARGET_NAME}Config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${TARGET_NAME}
COMPONENT DEV
)
# Формирование файла для pkg-config
file(WRITE "${PROJECT_BINARY_DIR}/${TARGET_NAME}.pc"
"prefix=${CMAKE_INSTALL_PREFIX}\n"
"exec_prefix=${CMAKE_INSTALL_PREFIX}\n"
"includedir=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}\n")
if(NOT TARGET_TYPE STREQUAL "INTERFACE")
file(APPEND "${PROJECT_BINARY_DIR}/${TARGET_NAME}.pc"
"libdir=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}\n")
endif()
file(APPEND "${PROJECT_BINARY_DIR}/${TARGET_NAME}.pc"
"\n"
"Name: ${TARGET_NAME}\n"
"Description: ${TARGET_NAME} library\n"
"Version: ${PROJECT_VERSION}\n"
"\n"
"Requires:\n"
"Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}\n")
if(NOT TARGET_TYPE STREQUAL "INTERFACE")
file(APPEND "${PROJECT_BINARY_DIR}/${TARGET_NAME}.pc"
"Libs: -L${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} -l${TARGET_NAME}\n")
endif()
# Установка файла для pkg-config
install(
FILES "${PROJECT_BINARY_DIR}/${TARGET_NAME}.pc"
COMPONENT DEV
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
if(TARGET_TYPE STREQUAL "OBJECT")
# Установка динамической библиотеки
if(TARGET ${TARGET_NAME}_shared)
install(
TARGETS ${TARGET_NAME}_shared
EXPORT ${TARGET_NAME}Targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT LIB
)
endif()
if(TARGET ${TARGET_NAME}_static)
# Установка статической библиотеки
install(
TARGETS ${TARGET_NAME}_static
EXPORT ${TARGET_NAME}Targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT STATIC
)
endif()
endif()
if(TARGET_TYPE STREQUAL "INTERFACE")
# Установка библиотеки из заголовочных файлов
target_include_directories(${TARGET_NAME} SYSTEM INTERFACE $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
install(
TARGETS ${TARGET_NAME}
EXPORT ${TARGET_NAME}Targets
COMPONENT LIB
)
endif()
endfunction()