diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b09753..da76ec0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,11 +13,6 @@ set(${PROJECT_NAME}_CONTACT unknown) # Рекомендуемый способ подключения MyxCMake include(cmake/myx_setup.cmake) -# Поиск пакетов -myx_find_required_packages( - Qt5 Core - Qt5Private Core) - # Цель для создания исполняемого файла add_executable(${PROJECT_NAME}) @@ -28,7 +23,7 @@ myx_target_setup(${PROJECT_NAME} ) # Настройка Qt для цели -myx_qt5_target_setup(${PROJECT_NAME} +myx_qt_target_setup(${PROJECT_NAME} COMPONENTS Core PRIVATE Core PRIVATE_MOC diff --git a/cmake/myx/MyxCMakeConfig.cmake b/cmake/myx/MyxCMakeConfig.cmake index 43c3934..e4ada74 100644 --- a/cmake/myx/MyxCMakeConfig.cmake +++ b/cmake/myx/MyxCMakeConfig.cmake @@ -61,7 +61,7 @@ include(${MYX_CMAKE_LIB_DIR}/AddExecutable.cmake) include(${MYX_CMAKE_LIB_DIR}/AddInterfaceLibrary.cmake) include(${MYX_CMAKE_LIB_DIR}/AddObjectLibrary.cmake) include(${MYX_CMAKE_LIB_DIR}/TargetSetup.cmake) -include(${MYX_CMAKE_LIB_DIR}/Qt5TargetSetup.cmake) +include(${MYX_CMAKE_LIB_DIR}/macro/QtTargetSetup.cmake) include(${MYX_CMAKE_LIB_DIR}/uncrustify/Uncrustify.cmake) include(${MYX_CMAKE_LIB_DIR}/doc/Doxygen.cmake) diff --git a/cmake/myx/MyxCMakeConfigVersion.cmake b/cmake/myx/MyxCMakeConfigVersion.cmake index 898c71d..5eee7a2 100644 --- a/cmake/myx/MyxCMakeConfigVersion.cmake +++ b/cmake/myx/MyxCMakeConfigVersion.cmake @@ -1,4 +1,4 @@ -set(MYX_CMAKE_PACKAGE_VERSION "2.3.8") +set(MYX_CMAKE_PACKAGE_VERSION "2.4.2") if(MYX_CMAKE_PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) set(PACKAGE_VERSION_COMPATIBLE FALSE) else() diff --git a/cmake/myx/lib/AddExternalTarget.cmake b/cmake/myx/lib/AddExternalTarget.cmake new file mode 100644 index 0000000..b1f562b --- /dev/null +++ b/cmake/myx/lib/AddExternalTarget.cmake @@ -0,0 +1,79 @@ +#[=======================================================================[.rst: +myx_add_external_target +----------------------- + +Функция для подключения целей из внешних проектов:: + + myx_add_external_target(TARGET_NAME + [ MODULES_PATH modules_path ] | + [ GIT_REPOSITORY url ] | + [ GIT_TAG tag ] | + [ LOCAL_PATH local_path ] ) + +Обязательный параметр: `TARGET_NAME` - имя цели, содержащейся во внешнем проекте. +Параметр `MODULES_PATH` содержит имя каталога, в который будут загружаться +внешние проекты (по умолчанию `modules`). Параметр `GIT_REPOSITORY` содержит +адрес внешнего проекта, который нужно загрузить с помощью git. Параметр `GIT_TAG` +содержит используемые метку, идентификатор коммита или ветку в репозитории. +Параметр `LOCAL_PATH` используется для указания пути к подкаталогу, находящемуся +вне текущего проекта. Его следует указывать только при вызове функции из +вспомогательного файла `external_targets.cmake`. + +#]=======================================================================] + + +find_package(Git) + +function(myx_add_external_target TARGET_NAME) + set(options) + set(oneValueArgs) + set(multiValueArgs MODULES_PATH GIT_REPOSITORY GIT_TAG LOCAL_PATH) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(TARGET ${TARGET_NAME}) + return() + endif() + + if(ARG_LOCAL_PATH) + myx_message_notice("Using directory ${ARG_LOCAL_PATH} to build target ${TARGET_NAME}") + add_subdirectory(${ARG_LOCAL_PATH} ${CMAKE_BINARY_DIR}/${TARGET_NAME} EXCLUDE_FROM_ALL) + return() + endif() + + if(NOT ARG_MODULES_PATH) + set(ARG_MODULES_PATH modules) + endif() + + if(CMAKE_SCRIPT_MODE_FILE) + set(PROJECT_SOURCE_DIR ${CMAKE_SOURCE_DIR}) + endif() + set(ARG_MODULES_PATH ${PROJECT_SOURCE_DIR}/${ARG_MODULES_PATH}) + + if(NOT IS_DIRECTORY ${ARG_MODULES_PATH}) + execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${ARG_MODULES_PATH}) + endif() + + if(GIT_EXECUTABLE) + if(NOT IS_DIRECTORY ${ARG_MODULES_PATH}/${TARGET_NAME}) + execute_process(COMMAND ${GIT_EXECUTABLE} clone ${ARG_GIT_REPOSITORY} ${TARGET_NAME} + WORKING_DIRECTORY ${ARG_MODULES_PATH}) + else() + execute_process(COMMAND ${GIT_EXECUTABLE} fetch + WORKING_DIRECTORY ${ARG_MODULES_PATH}/${TARGET_NAME}) + endif() + execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${ARG_GIT_TAG} + WORKING_DIRECTORY ${ARG_MODULES_PATH}/${TARGET_NAME}) + endif() + + if(NOT CMAKE_SCRIPT_MODE_FILE) + add_subdirectory(${ARG_MODULES_PATH}/${TARGET_NAME} EXCLUDE_FROM_ALL) + endif() + + if(NOT TARGET ${TARGET_NAME}) + myx_message_fatal_error("Target ${TARGET_NAME} is not found.") + endif() + +endfunction(myx_add_external_target) + +include("${PROJECT_SOURCE_DIR}/external_targets.cmake" OPTIONAL) + diff --git a/cmake/myx/lib/AddInterfaceLibrary.cmake b/cmake/myx/lib/AddInterfaceLibrary.cmake new file mode 100644 index 0000000..f8eedd3 --- /dev/null +++ b/cmake/myx/lib/AddInterfaceLibrary.cmake @@ -0,0 +1,154 @@ +#[=======================================================================[.rst: +myx_add_interface_library +------------------------- + +Вспомогательная функция для создания интерфейсной библиотеки:: + + myx_add_interface_library(TARGET_NAME + [ PACKAGES packages ] | + [ LINK_LIBRARIES link_libraries ] | + [ OUTPUT_NAME output_name ] | + [ HEADERS headers ]) + +Обязательные параметры: `TARGET_NAME` - имя библиотеки. +Параметр `OUTPUT_NAME` определяет базовое имя выходных файлов. +Все остальные параметры передаются в стандартную функцию `add_library()` + +#]=======================================================================] + +include_guard(GLOBAL) + +include(CMakePackageConfigHelpers) + +if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + set(MYX_CMAKE_LIB_DIR_BACKPORT "${CMAKE_CURRENT_LIST_DIR}") +endif() + +function(myx_add_interface_library TARGET_NAME) + if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + set(CMAKE_CURRENT_FUNCTION_LIST_DIR ${MYX_CMAKE_LIB_DIR_BACKPORT}) + endif() + + if(TARGET ${TARGET_NAME}) + myx_message_fatal_error("Target ${TARGET_NAME} already exists") + endif() + + set(options) + set(oneValueArgs OUTPUT_NAME) + set(multiValueArgs HEADERS LINK_LIBRARIES PACKAGES) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT ARG_OUTPUT_NAME) + set(ARG_OUTPUT_NAME ${TARGET_NAME}) + endif() + + # Вызов стандартной функции `add_library()` + if(${CMAKE_VERSION} VERSION_LESS "3.19.0") + add_library(${TARGET_NAME} INTERFACE) + target_sources(${TARGET_NAME} INTERFACE $) + else() + add_library(${TARGET_NAME} INTERFACE ${ARG_HEADERS}) + endif() + + + foreach(__iter ${ARG_PACKAGES}) + target_include_directories(${TARGET_NAME} INTERFACE ${${__iter}_INCLUDE_DIRS}) + target_compile_definitions(${TARGET_NAME} INTERFACE ${${__iter}_COMPILE_DEFINITIONS}) + endforeach() + + if(ARG_LINK_LIBRARIES) + target_link_libraries(${TARGET_NAME} INTERFACE ${ARG_LINK_LIBRARIES}) + if(${CMAKE_VERSION} VERSION_GREATER "3.15.0") + foreach(__lib ${ARG_LINK_LIBRARIES}) + if(TARGET ${__lib}) + install( + TARGETS ${__lib} + EXPORT ${TARGET_NAME}Targets + COMPONENT DEV) + endif() + endforeach() + endif() + endif() + + # Библиотека, состоящая только из заголовочных файлов не требует сборки. + # Стандартные пути к заголовочным файлам + target_include_directories(${TARGET_NAME} INTERFACE + $ + $ + ) + + # Если вызов был выполнен не из проекта верхнего уровня, + # то созданная цель исключается из цели `all`. + # При этом сама цель `${TARGET_NAME}` может участвовать в сборке, + # если окажется в перечне зависимостей. + if(NOT PROJECT_IS_TOP_LEVEL) + if(${CMAKE_VERSION} VERSION_GREATER "3.17.0") + set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL True) + else() + set_target_properties(${TARGET_NAME} PROPERTIES INTERFACE_EXCLUDE_FROM_ALL True) + endif() + 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" + "\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") + + # Установка файла для pkg-config + install( + FILES "${PROJECT_BINARY_DIR}/${TARGET_NAME}.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" + COMPONENT DEV) + + # Установка библиотеки из заголовочных файлов + target_include_directories(${TARGET_NAME} SYSTEM INTERFACE $) + install( + TARGETS ${TARGET_NAME} + EXPORT ${TARGET_NAME}Targets + COMPONENT DEV) + + # Установка публичных заголовочных файлов + if(PROJECT_IS_TOP_LEVEL AND ARG_HEADERS) + myx_install_relative(${PROJECT_SOURCE_DIR} + FILES ${ARG_HEADERS} + DESTINATION ${CMAKE_INSTALL_PREFIX} + COMPONENT DEV) + endif() +endfunction() diff --git a/cmake/myx/lib/AddObjectLibrary.cmake b/cmake/myx/lib/AddObjectLibrary.cmake new file mode 100644 index 0000000..58b16bf --- /dev/null +++ b/cmake/myx/lib/AddObjectLibrary.cmake @@ -0,0 +1,199 @@ +#[=======================================================================[.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.0") + 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.0") + 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 + $ + PRIVATE + $ + $ + ) + + # Сборка позиционно-независимых объектных файлов нужна + # для создания динамической библиотеки + 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_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_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() diff --git a/cmake/myx/lib/Toolchains.cmake b/cmake/myx/lib/Toolchains.cmake new file mode 100644 index 0000000..963098d --- /dev/null +++ b/cmake/myx/lib/Toolchains.cmake @@ -0,0 +1,56 @@ +include_guard(GLOBAL) + +if(CMAKE_SYSTEM_NAME STREQUAL Linux) + set(MYX_CMAKE_LSB_DISTRIBUTOR_ID "unknown") + set(MYX_CMAKE_LSB_CODENAME "unknown") + set(MYX_CMAKE_LSB_RELEASE_VERSION "unknown") + + if(CMAKE_CROSSCOMPILING) + return() + endif() + + if(EXISTS /etc/mcst_version) + set(MYX_CMAKE_LSB_DISTRIBUTOR_ID "ElbrusD") + set(MYX_CMAKE_LSB_CODENAME "Jessie") + execute_process(COMMAND cat /etc/mcst_version + OUTPUT_VARIABLE MYX_CMAKE_LSB_RELEASE_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + else() + find_program(LSB_RELEASE_EXECUTABLE lsb_release) + # cmake-format: off + if(LSB_RELEASE_EXECUTABLE) + execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -si + OUTPUT_VARIABLE MYX_CMAKE_LSB_DISTRIBUTOR_ID + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -sc + OUTPUT_VARIABLE MYX_CMAKE_LSB_CODENAME + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -sr + OUTPUT_VARIABLE MYX_CMAKE_LSB_RELEASE_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + # cmake-format: on + endif() +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + include("${MYX_CMAKE_TOOLCHAINS_DIR}/GCC.cmake") +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + include("${MYX_CMAKE_TOOLCHAINS_DIR}/Clang.cmake") +endif() + +if((MYX_CMAKE_LSB_DISTRIBUTOR_ID STREQUAL "AstraLinuxSE") AND + (MYX_CMAKE_LSB_CODENAME STREQUAL "smolensk") AND + (MYX_CMAKE_LSB_RELEASE_VERSION STREQUAL "1.5")) + include("${MYX_CMAKE_TOOLCHAINS_DIR}/AstraLinuxSE-1.5.cmake") + return() +endif() + +if((MYX_CMAKE_LSB_DISTRIBUTOR_ID STREQUAL "ElbrusD") AND + (MYX_CMAKE_LSB_CODENAME STREQUAL "Jessie") AND + (MYX_CMAKE_LSB_RELEASE_VERSION VERSION_GREATER "1.4")) + include("${MYX_CMAKE_TOOLCHAINS_DIR}/ElbrusD-1.4.cmake") + return() +endif() diff --git a/cmake/myx/lib/doc/Doxygen.cmake b/cmake/myx/lib/doc/Doxygen.cmake index 569a048..6cb2fe0 100644 --- a/cmake/myx/lib/doc/Doxygen.cmake +++ b/cmake/myx/lib/doc/Doxygen.cmake @@ -2,6 +2,8 @@ if(${CMAKE_VERSION} VERSION_LESS "3.17.0") set(MYX_CMAKE_LIB_DOC_DIR_BACKPORT "${CMAKE_CURRENT_LIST_DIR}") endif() +find_package(Doxygen) + function(myx_doc_doxygen TARGET_NAME) if(${CMAKE_VERSION} VERSION_LESS "3.17.0") set(CMAKE_CURRENT_FUNCTION_LIST_DIR ${MYX_CMAKE_LIB_DOC_DIR_BACKPORT}) @@ -11,7 +13,6 @@ function(myx_doc_doxygen TARGET_NAME) return() endif() - find_package(Doxygen) if(DOXYGEN_FOUND) set(DOXYGEN_FOUND ON CACHE STRING "Doxygen documentation generator enabled" FORCE) set(DOXYGEN_EXECUTABLE "${DOXYGEN_EXECUTABLE}" CACHE STRING "Path to Doxygen executable") diff --git a/cmake/myx/lib/macro/FindPackages.cmake b/cmake/myx/lib/macro/FindPackages.cmake index eecd465..b18d17b 100644 --- a/cmake/myx/lib/macro/FindPackages.cmake +++ b/cmake/myx/lib/macro/FindPackages.cmake @@ -1,36 +1,54 @@ +#[=======================================================================[.rst: +myx_find_packages +----------------- + +Вспомогательная функция для поиска зависимостей:: + + myx_find_packages() + +Упрощённый способ поиска необходимых и опциональных зависимостей. +Для поиска зависимостей с учётом особенных требований (например, номер версии) +следует использовать функции `find_package` и `pkg_check_modules`. +Параметр `REQUIRED` содержит перечисление необходимых зависимостей +для поиска с помощью функции `find_package`. +Параметр `OPTIONAL` содержит перечисление опциональных зависимостей +для поиска с помощью функции `find_package`. +Параметр `PKG_REQUIRED` содержит перечисление необходимых зависимостей +для поиска с помощью функции `pkg_check_modules`. +Параметр `PKG_OPTIONAL` содержит перечисление опциональных зависимостей +для поиска с помощью функции `pkg_check_modules`. + +#]=======================================================================] + include_guard(GLOBAL) -macro(myx_find_required_packages) +macro(myx_find_packages) set(options) set(oneValueArgs) - set(multiValueArgs PACKAGES Boost Qt5 Qt5Private Qt6 Qt6Private) + set(multiValueArgs REQUIRED OPTIONAL PKG_REQUIRED PKG_OPTIONAL) cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - foreach(iter ${ARG_PACKAGES}) + foreach(iter ${ARG_REQUIRED}) find_package(${iter} REQUIRED) endforeach() - if(ARG_Boost) - find_package(Boost COMPONENTS ${ARG_Boost} REQUIRED) - endif() + foreach(iter ${ARG_OPTIONAL}) + find_package(${iter}) + endforeach() - if(ARG_Qt5) - find_package(Qt5 COMPONENTS ${ARG_Qt5} REQUIRED) - endif() - - if(ARG_Qt5Private) - foreach(iter ${ARG_Qt5Private}) - find_package("Qt5${iter}" COMPONENTS Private REQUIRED) + if(ARG_PKG_REQUIRED) + find_package(PkgConfig REQUIRED) + foreach(iter ${ARG_PKG_REQUIRED}) + string(TOUPPER ${iter} iu) + pkg_check_modules(${iu} REQUIRED ${iter}) endforeach() endif() - if(ARG_Qt6) - find_package(Qt6 COMPONENTS ${ARG_Qt6} REQUIRED) - endif() - - if(ARG_Qt6Private) - foreach(iter ${ARG_Qt6Private}) - find_package("Qt6${iter}" COMPONENTS Private REQUIRED) + if(ARG_PKG_OPTIONAL) + find_package(PkgConfig REQUIRED) + foreach(iter ${ARG_PKG_OPTIONAL}) + string(TOUPPER ${iter} iu) + pkg_check_modules(${iu} ${iter}) endforeach() endif() @@ -41,4 +59,4 @@ macro(myx_find_required_packages) unset(multiValueArgs) unset(oneValueArgs) unset(options) -endmacro(myx_find_required_packages) +endmacro(myx_find_packages) diff --git a/cmake/myx/lib/macro/GTest.cmake b/cmake/myx/lib/macro/GTest.cmake new file mode 100644 index 0000000..9ff6b92 --- /dev/null +++ b/cmake/myx/lib/macro/GTest.cmake @@ -0,0 +1,30 @@ +include_guard(GLOBAL) + +macro(myx_add_gtest TARGET_NAME) + set(options) + set(oneValueArgs) + set(multiValueArgs) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + add_executable(${TARGET_NAME} ${ARG_UNPARSED_ARGUMENTS}) + + find_package(GTest) + if(GTest_FOUND) + target_link_libraries(${TARGET_NAME} PRIVATE GTest::GTest GTest::Main) + else() + if((NOT TARGET gtest) AND (NOT TARGET gtest_main)) + add_subdirectory(/usr/src/googletest/googletest ${CMAKE_BINARY_DIR}/gtest) + endif() + target_link_libraries(${TARGET_NAME} PRIVATE gtest gtest_main) + endif() + + add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME}) + foreach(__iter IN LISTS oneValueArgs multiValueArgs) + unset(ARG_${__iter}) + endforeach() + unset(ARG_UNPARSED_ARGUMENTS) + unset(multiValueArgs) + unset(oneValueArgs) + unset(options) +endmacro() + diff --git a/cmake/myx/lib/macro/QTest.cmake b/cmake/myx/lib/macro/QTest.cmake new file mode 100644 index 0000000..be0dbb6 --- /dev/null +++ b/cmake/myx/lib/macro/QTest.cmake @@ -0,0 +1,40 @@ +include_guard(GLOBAL) + +macro(myx_add_qtest TARGET_NAME) + set(options) + set(oneValueArgs) + set(multiValueArgs) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + find_package(Qt5 COMPONENTS Core Test REQUIRED) + if(NOT Qt5Test_FOUND) + myx_message_fatal_error("Qt testing framework is not found") + return() + endif() + + foreach(filename ${ARG_UNPARSED_ARGUMENTS}) + get_filename_component(basename ${filename} NAME_WE) + list(APPEND cpps "${basename}.cpp") + list(APPEND hpps "${basename}.hpp") + qt5_wrap_cpp(moc "${basename}.hpp") + list(APPEND mocs "${moc}") + endforeach() + + add_executable(${TARGET_NAME} ${mocs} ${cpps} ${hpps}) + target_link_libraries(${TARGET_NAME} PRIVATE Qt5::Core Qt5::Test) + + add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME}) + + unset(cpps) + unset(hpps) + unset(moc) + unset(mocs) + foreach(__iter IN LISTS oneValueArgs multiValueArgs) + unset(ARG_${__iter}) + endforeach() + unset(ARG_UNPARSED_ARGUMENTS) + unset(multiValueArgs) + unset(oneValueArgs) + unset(options) +endmacro() + diff --git a/cmake/myx/lib/Qt5TargetSetup.cmake b/cmake/myx/lib/macro/QtTargetSetup.cmake similarity index 55% rename from cmake/myx/lib/Qt5TargetSetup.cmake rename to cmake/myx/lib/macro/QtTargetSetup.cmake index 23d0197..861e6fb 100644 --- a/cmake/myx/lib/Qt5TargetSetup.cmake +++ b/cmake/myx/lib/macro/QtTargetSetup.cmake @@ -1,43 +1,85 @@ include_guard(GLOBAL) -function(myx_qt5_target_setup TARGET_NAME) +macro(myx_qt_target_setup TARGET_NAME) set(options) - set(oneValueArgs) + set(oneValueArgs VERSION) set(multiValueArgs COMPONENTS PRIVATE PUBLIC_MOC PRIVATE_MOC UI QRC LANGS) cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if(NOT ARG_VERSION) + set(ARG_VERSION "5") + endif() + + if(NOT (ARG_VERSION STREQUAL "5" OR ARG_VERSION STREQUAL "6")) + myx_message_fatal_error("Supported Qt versions are 5 and 6") + endif() + + foreach(iter ${ARG_COMPONENTS}) + find_package(Qt${ARG_VERSION} COMPONENTS ${iter} REQUIRED) + endforeach() + + foreach(iter ${ARG_PRIVATE}) + find_package("Qt${ARG_VERSION}${iter}" COMPONENTS Private REQUIRED) + endforeach() + + myx_qt_target_setup_post(${ARGV}) + + foreach(__iter IN LISTS oneValueArgs multiValueArgs) + unset(ARG_${__iter}) + endforeach() + unset(ARG_UNPARSED_ARGUMENTS) + unset(multiValueArgs) + unset(oneValueArgs) + unset(options) +endmacro() + +function(myx_qt_target_setup_post TARGET_NAME) + set(options) + set(oneValueArgs VERSION) + set(multiValueArgs COMPONENTS PRIVATE PUBLIC_MOC PRIVATE_MOC UI QRC LANGS) + + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT ARG_VERSION) + set(ARG_VERSION "5") + endif() + + if(NOT (ARG_VERSION STREQUAL "5" OR ARG_VERSION STREQUAL "6")) + myx_message_fatal_error("Supported Qt versions are 5 and 6") + endif() + get_target_property(__target_type ${TARGET_NAME} TYPE) foreach(iter ${ARG_COMPONENTS}) if(__target_type STREQUAL "INTERFACE_LIBRARY") - target_include_directories(${TARGET_NAME} INTERFACE ${Qt5${iter}_INCLUDE_DIRS}) + target_include_directories(${TARGET_NAME} INTERFACE ${Qt${ARG_VERSION}${iter}_INCLUDE_DIRS}) else() - target_include_directories(${TARGET_NAME} PRIVATE ${Qt5${iter}_INCLUDE_DIRS}) + target_include_directories(${TARGET_NAME} PRIVATE ${Qt${ARG_VERSION}${iter}_INCLUDE_DIRS}) endif() if(NOT iter STREQUAL "LinguistTools") if(__target_type STREQUAL "EXECUTABLE") - target_link_libraries(${TARGET_NAME} PRIVATE "Qt5::${iter}") + target_link_libraries(${TARGET_NAME} PRIVATE "Qt${ARG_VERSION}::${iter}") endif() if(__target_type STREQUAL "SHARED_LIBRARY") - target_link_libraries(${TARGET_NAME} PUBLIC "Qt5::${iter}") + target_link_libraries(${TARGET_NAME} PUBLIC "Qt${ARG_VERSION}::${iter}") endif() if((${CMAKE_VERSION} VERSION_GREATER "3.8.0") AND (__target_type STREQUAL "OBJECT_LIBRARY")) - target_link_libraries(${TARGET_NAME} PUBLIC "Qt5::${iter}") + target_link_libraries(${TARGET_NAME} PUBLIC "Qt${ARG_VERSION}::${iter}") endif() endif() endforeach() foreach(iter ${ARG_PRIVATE}) if(__target_type STREQUAL "INTERFACE_LIBRARY") - target_include_directories(${TARGET_NAME} INTERFACE ${Qt5${iter}_PRIVATE_INCLUDE_DIRS}) + target_include_directories(${TARGET_NAME} INTERFACE ${Qt${ARG_VERSION}${iter}_PRIVATE_INCLUDE_DIRS}) else() - target_include_directories(${TARGET_NAME} PRIVATE ${Qt5${iter}_PRIVATE_INCLUDE_DIRS}) + target_include_directories(${TARGET_NAME} PRIVATE ${Qt${ARG_VERSION}${iter}_PRIVATE_INCLUDE_DIRS}) endif() endforeach() if(__target_type STREQUAL "EXECUTABLE") - target_compile_options(${TARGET_NAME} PRIVATE ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}) + target_compile_options(${TARGET_NAME} PRIVATE ${Qt${ARG_VERSION}Core_EXECUTABLE_COMPILE_FLAGS}) endif() if(ARG_PUBLIC_MOC) @@ -51,15 +93,27 @@ function(myx_qt5_target_setup TARGET_NAME) endif() if(ARG_PUBLIC_MOC OR ARG_PRIVATE_MOC) - qt5_wrap_cpp(moc_cpp ${ARG_PUBLIC_MOC} ${ARG_PRIVATE_MOC}) + if(ARG_VERSION STREQUAL "5") + qt5_wrap_cpp(moc_cpp ${ARG_PUBLIC_MOC} ${ARG_PRIVATE_MOC}) + else() + qt6_wrap_cpp(moc_cpp ${ARG_PUBLIC_MOC} ${ARG_PRIVATE_MOC}) + endif() endif() if(ARG_QRC) - qt5_add_resources(qrc_cpp ${ARG_QRC}) + if(ARG_VERSION STREQUAL "5") + qt5_add_resources(qrc_cpp ${ARG_QRC}) + else() + qt6_add_resources(qrc_cpp ${ARG_QRC}) + endif() endif() if(ARG_UI AND "Widgets" IN_LIST ARG_COMPONENTS) - qt5_wrap_ui(ui_h ${ARG_UI}) + if(ARG_VERSION STREQUAL "5") + qt5_wrap_ui(ui_h ${ARG_UI}) + else() + qt6_wrap_ui(ui_h ${ARG_UI}) + endif() set_property(TARGET ${TARGET_NAME} APPEND PROPERTY TR_FILES ${ARG_UI}) # TODO target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_BINARY_DIR}) @@ -79,9 +133,15 @@ function(myx_qt5_target_setup TARGET_NAME) foreach(iter ${ARG_LANGS}) # Создание или обновление файла переводов в каталоге ${PROJECT_SOURCE_DIR}/l10n # и его компиляция в каталог ${PROJECT_BINARY_DIR} - qt5_create_translation(qm ${tr} - "${PROJECT_SOURCE_DIR}/l10n/${TARGET_NAME}_${iter}.ts" - OPTIONS -I ${PROJECT_SOURCE_DIR}/include -I ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}) + if(ARG_VERSION STREQUAL "5") + qt5_create_translation(qm ${tr} + "${PROJECT_SOURCE_DIR}/l10n/${TARGET_NAME}_${iter}.ts" + OPTIONS -I ${PROJECT_SOURCE_DIR}/include -I ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}) + else() + qt6_create_translation(qm ${tr} + "${PROJECT_SOURCE_DIR}/l10n/${TARGET_NAME}_${iter}.ts" + OPTIONS -I ${PROJECT_SOURCE_DIR}/include -I ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}) + endif() # Добавление записи для скомпилированного файла переводов в ресурсный файл file(APPEND ${PROJECT_BINARY_DIR}/${TARGET_NAME}_l10n.qrc "${TARGET_NAME}_${iter}.qm\n") @@ -91,7 +151,11 @@ function(myx_qt5_target_setup TARGET_NAME) # Окончание файла ресурсов file(APPEND ${PROJECT_BINARY_DIR}/${TARGET_NAME}_l10n.qrc "\n") # Компиляция файла ресурсов с переводами - qt5_add_resources(qrc_l10n ${PROJECT_BINARY_DIR}/${TARGET_NAME}_l10n.qrc) + if(ARG_VERSION STREQUAL "5") + qt5_add_resources(qrc_l10n ${PROJECT_BINARY_DIR}/${TARGET_NAME}_l10n.qrc) + else() + qt6_add_resources(qrc_l10n ${PROJECT_BINARY_DIR}/${TARGET_NAME}_l10n.qrc) + endif() target_sources(${TARGET_NAME} PRIVATE ${qrc_l10n}) endif() unset(tr) diff --git a/cmake/myx/lib/toolchains/AstraLinuxSE-1.5.cmake b/cmake/myx/lib/toolchains/AstraLinuxSE-1.5.cmake new file mode 100644 index 0000000..df9db4a --- /dev/null +++ b/cmake/myx/lib/toolchains/AstraLinuxSE-1.5.cmake @@ -0,0 +1,8 @@ +find_program(CMAKE_AR NAMES "/usr/bin/x86_64-linux-gnu-gcc-ar-4.7") +find_program(CMAKE_NM NAMES "/usr/bin/x86_64-linux-gnu-gcc-nm-4.7") +find_program(CMAKE_RANLIB NAMES "/usr/bin/x86_64-linux-gnu-gcc-ranlib-4.7") + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_EXTENSIONS ON) +check_enable_cxx_compiler_flag(-Wno-shadow) + diff --git a/cmake/myx/lib/toolchains/Clang.cmake b/cmake/myx/lib/toolchains/Clang.cmake new file mode 100644 index 0000000..e5f1d62 --- /dev/null +++ b/cmake/myx/lib/toolchains/Clang.cmake @@ -0,0 +1,3 @@ +if(CMAKE_COLOR_MAKEFILE) + check_enable_cxx_compiler_flag(-fcolor-diagnostics) +endif() diff --git a/cmake/myx/lib/toolchains/ElbrusD-1.4.cmake b/cmake/myx/lib/toolchains/ElbrusD-1.4.cmake new file mode 100644 index 0000000..29b46c6 --- /dev/null +++ b/cmake/myx/lib/toolchains/ElbrusD-1.4.cmake @@ -0,0 +1,9 @@ +find_program(CMAKE_AR NAMES "/usr/${CMAKE_SYSTEM_PROCESSOR}-linux/bin/ar") +find_program(CMAKE_NM NAMES "/usr/${CMAKE_SYSTEM_PROCESSOR}-linux/bin/nm") +find_program(CMAKE_RANLIB NAMES "/usr/${CMAKE_SYSTEM_PROCESSOR}-linux/bin/ranlib") + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_EXTENSIONS ON) +check_enable_cxx_compiler_flag(-Wno-invalid-offsetof) +list(APPEND CMAKE_LIBRARY_PATH "/usr/lib/e2k-linux-gnu") + diff --git a/cmake/myx/lib/toolchains/GCC.cmake b/cmake/myx/lib/toolchains/GCC.cmake new file mode 100644 index 0000000..3ac7ec8 --- /dev/null +++ b/cmake/myx/lib/toolchains/GCC.cmake @@ -0,0 +1,3 @@ +if(CMAKE_COLOR_MAKEFILE) + check_enable_cxx_compiler_flag(-fdiagnostics-color=auto) +endif() diff --git a/cmake/myx_setup.cmake b/cmake/myx_setup.cmake index 4534a05..cd2f5a2 100644 --- a/cmake/myx_setup.cmake +++ b/cmake/myx_setup.cmake @@ -20,11 +20,11 @@ if(ENV{MYX_CMAKE_DIR}) set(MYX_CMAKE_DIR $ENV{MYX_CMAKE_DIR}) endif() if(MYX_CMAKE_DIR) - find_package(MyxCMake 2.3.8 REQUIRED CONFIG PATHS ${MYX_CMAKE_DIR} NO_DEFAULT_PATH) + find_package(MyxCMake 2.4.2 REQUIRED CONFIG PATHS ${MYX_CMAKE_DIR} NO_DEFAULT_PATH) myx_message_notice("== MyxCMake directory: ${MyxCMake_CONFIG} ==") else() if(MYX_CMAKE_USE_SYSTEM) - find_package(MyxCMake 2.3.8 REQUIRED) + find_package(MyxCMake 2.4.2 REQUIRED) myx_message_notice("== MyxCMake directory: ${MyxCMake_CONFIG} ==") else() include(${PROJECT_SOURCE_DIR}/cmake/myx/MyxCMakeConfig.cmake)