#[=======================================================================[.rst:
myx_add_object_library
----------------------

Вспомогательная функция для создания объектной библиотеки::

    myx_add_object_library(TARGET_NAME
      [ OUTPUT_NAME output_name ] |
      [ NO_EXPORT ] |
      [ EXPORT_FILE_NAME file_name ] |
      [ EXPORT_BASE_NAME base_name ])

Обязательные параметры: `TARGET_NAME` - имя библиотеки.
Параметр `OUTPUT_NAME` определяет базовое имя выходных файлов.
Если указана опция `NO_EXPORT`, то файл экспорта не генерируется.
Параметр `EXPORT_FILE_NAME` задаёт имя заголовочного файла экспортируемых
переменных, а `EXPORT_BASE_NAME` - базовый суффикс для формирования имён переменных.
Все остальные параметры передаются в стандартную функцию `add_library()`

#]=======================================================================]

include_guard(GLOBAL)

if(${CMAKE_VERSION} VERSION_LESS 3.17)
  set(MYX_CMAKE_LIB_DIR_BACKPORT "${CMAKE_CURRENT_LIST_DIR}")
endif()

function(myx_add_object_library TARGET_NAME)
  if(${CMAKE_VERSION} VERSION_LESS 3.17)
    set(CMAKE_CURRENT_FUNCTION_LIST_DIR ${MYX_CMAKE_LIB_DIR_BACKPORT})
  endif()

  include(CMakePackageConfigHelpers)

  set(options NO_EXPORT)
  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} OBJECT ${ARG_UNPARSED_ARGUMENTS})

  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 ARG_NO_EXPORT)
    include(GenerateExportHeader)
    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}")
  endif()

  # Цель для создания динамической библиотеки из объектных файлов
  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()

  # Если вызов был выполнен не из проекта верхнего уровня,
  # то созданная цель исключается из цели `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"
    "libdir=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}\n"
    "\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"
    "Libs: -L${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} -l${TARGET_NAME}\n")

  # Установка файла для pkg-config
  install(
    FILES "${PROJECT_BINARY_DIR}/${TARGET_NAME}.pc"
    COMPONENT DEV
    DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")

  # Установка динамической библиотеки
  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()
endfunction()