From 85d550a14798c63229caa85744395431968c7478 Mon Sep 17 00:00:00 2001 From: Andrey Astafyev Date: Sun, 30 Jul 2023 15:49:51 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20MyxCMake?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 14 ++- cmake/myx/MyxCMakeConfig.cmake | 2 +- cmake/myx/MyxCMakeConfigVersion.cmake | 2 +- cmake/myx/lib/AddInterfaceLibrary.cmake | 6 +- cmake/myx/lib/doc/Doxygen.cmake | 3 +- cmake/myx/lib/macro/FindPackages.cmake | 60 ++++++++---- cmake/myx/lib/macro/QTest.cmake | 2 +- .../QtTargetSetup.cmake} | 98 +++++++++++++++---- cmake/myx_setup.cmake | 4 +- 9 files changed, 138 insertions(+), 53 deletions(-) rename cmake/myx/lib/{Qt5TargetSetup.cmake => macro/QtTargetSetup.cmake} (55%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6ce162..252f02c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,14 +11,12 @@ project(myx-example-base VERSION 0.4.0 LANGUAGES CXX) include(cmake/myx_setup.cmake) # Поиск пакетов -myx_find_required_packages( - PACKAGES Git CURL PkgConfig Quadmath - Qt5 Core - Qt5Private Core) - -# Поиск библиотек с помощью pkgconfig -find_package(PkgConfig REQUIRED) -pkg_check_modules(UDEV udev) +myx_find_packages( + REQUIRED Git + OPTIONAL CURL Quadmath + PKG_REQUIRED udev + PKG_OPTIONAL glib-2.0 +) # Поиск с помощью функции find_package find_package(Boost 1.55.0 COMPONENTS system REQUIRED) 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/AddInterfaceLibrary.cmake b/cmake/myx/lib/AddInterfaceLibrary.cmake index 106e5a5..f8eedd3 100644 --- a/cmake/myx/lib/AddInterfaceLibrary.cmake +++ b/cmake/myx/lib/AddInterfaceLibrary.cmake @@ -50,6 +50,7 @@ function(myx_add_interface_library TARGET_NAME) 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}) @@ -71,7 +72,10 @@ function(myx_add_interface_library TARGET_NAME) # Библиотека, состоящая только из заголовочных файлов не требует сборки. # Стандартные пути к заголовочным файлам - target_include_directories(${TARGET_NAME} INTERFACE $) + target_include_directories(${TARGET_NAME} INTERFACE + $ + $ + ) # Если вызов был выполнен не из проекта верхнего уровня, # то созданная цель исключается из цели `all`. 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/QTest.cmake b/cmake/myx/lib/macro/QTest.cmake index f77cf04..be0dbb6 100644 --- a/cmake/myx/lib/macro/QTest.cmake +++ b/cmake/myx/lib/macro/QTest.cmake @@ -21,7 +21,7 @@ macro(myx_add_qtest TARGET_NAME) endforeach() add_executable(${TARGET_NAME} ${mocs} ${cpps} ${hpps}) - target_link_libraries(${TARGET_NAME} Qt5::Core Qt5::Test) + target_link_libraries(${TARGET_NAME} PRIVATE Qt5::Core Qt5::Test) add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME}) 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_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)