diff --git a/modules/ECMQtDeclareLoggingCategory.cmake b/modules/ECMQtDeclareLoggingCategory.cmake --- a/modules/ECMQtDeclareLoggingCategory.cmake +++ b/modules/ECMQtDeclareLoggingCategory.cmake @@ -2,17 +2,25 @@ # ECMQtDeclareLoggingCategory # --------------------------- # -# Generate declarations for logging categories in Qt5. +# This module provides the ``ecm_qt_declare_logging_category`` function for +# generating declarations for logging categories in Qt5, and the +# ``ecm_qt_install_logging_categories`` function for generating and installing +# a file in KDebugSettings format with the info about all those categories, +# as well as a file with info about any renamed categories if defined. +# To include in that file any logging categories that are manually defined +# also a function ``ecm_qt_export_logging_category`` is provided. # # :: # # ecm_qt_declare_logging_category( -# HEADER -# IDENTIFIER -# CATEGORY_NAME -# [DEFAULT_SEVERITY -# ]) +# HEADER +# IDENTIFIER +# CATEGORY_NAME +# [OLD_CATEGORY_NAMES [ [...]]] +# [DEFAULT_SEVERITY ] +# [EXPORT ] +# [DESCRIPTION ] +# ) # # A header file, ````, will be generated along with a corresponding # source file, which will be added to ````. These will provide a @@ -30,10 +38,109 @@ # # ```` may include namespaces (eg: ``foo::bar::IDENT``). # +# If ``EXPORT`` is passed, the category will be registered for the group id +# ````. Info about the categories of that group can then be +# generated in a file and installed by that group id with the +# ``ecm_qt_install_logging_categories`` function. In that case also ``DESCRIPTION`` +# will need to be passed, with ```` being a short single line text. +# And ``OLD_CATEGORY_NAMES`` can be used to inform about any renamings of the category, +# so user settings can be migrated. Since 5.68.0. +# # Since 5.14.0. +# +# :: +# +# ecm_qt_export_logging_category( +# IDENTIFIER +# CATEGORY_NAME +# [OLD_CATEGORY_NAMES [ [...]]] +# EXPORT +# DESCRIPTION +# [DEFAULT_SEVERITY ] +# ) +# +# Registers a logging category for being included in the generated and +# installed KDebugSettings files. To be used for categories who are declared by +# manual code or other ways instead of code generated with +# ``ecm_qt_declare_logging_category``. +# +# ```` may include namespaces (eg: ``foo::bar::IDENT``). +# +# ``EXPORT`` specifies the group id with which the category will be registered. +# Info about the categories of that group can then be generated in a file and +# installed by that group id with the ``ecm_qt_install_logging_categories`` function. +# +# ``DESCRIPTION`` specifies a short single line text describing the category. +# +# ``OLD_CATEGORY_NAMES`` can be used to inform about any renamings of the category, +# so user settings can be migrated. +# +# Since 5.68.0. +# +# :: +# +# ecm_qt_install_logging_categories( +# EXPORT +# [FILE ] +# DESTINATION +# [SORT] +# [COMPONENT ] +# ) +# +# Generates and installs a file in KDebugSettings format with the info about all +# the categories registered for the group ````, as well as a file with +# info about any renamed categories, if there are. +# +# The method call needs to be after the last ``ecm_qt_declare_logging_category`` +# call which uses the same ````. This can be in the same directory, or +# any subdirectory or parent directory. +# +# ``EXPORT`` specifies the group id of categories whose informatipn should be +# stored in the file generated and installed. +# +# ``FILE`` specifies the name of the file generated and installed. It will default +# to lower-cased ``.categories``. +# +# ``DESTINATION`` specifies where the generated file will be +# installed. +# +# IF ``SORT`` is set, entries will be sorted by identifiers. +# +# ``COMPONENT`` specifies the installation component name with which the install +# rules for the generated file are associated. +# +# Example usage: +# +# .. code-block:: cmake +# +# ecm_qt_declare_logging_category( +# MYPROJECT_SRCS +# HEADER "myproject_debug.h" +# IDENTIFIER "MYPROJECT_DEBUG" +# CATEGORY_NAME "myproject" +# OLD_CATEGORY_NAMES "myprojectlog" +# DESCRIPTION "My project" +# EXPORT MyProject +# ) +# +# ecm_qt_export_logging_category( +# IDENTIFIER "MYPROJECT_SUBMODULE_DEBUG" +# CATEGORY_NAME "myproject.submodule" +# DESCRIPTION "My project - submodule" +# EXPORT MyProject +# ) +# +# ecm_qt_install_logging_categories( +# EXPORT MyProject +# FILE myproject.categories +# DESTINATION "${KDE_INSTALL_LOGGINGCATEGORIESDIR}" +# ) +# +# Since 5.68.0. #============================================================================= # Copyright 2015 Alex Merry +# Copyright 2020 Friedrich W. H. Kossebau # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -63,10 +170,55 @@ set(_ECM_QT_DECLARE_LOGGING_CATEGORY_TEMPLATE_CPP "${CMAKE_CURRENT_LIST_DIR}/ECMQtDeclareLoggingCategory.cpp.in") set(_ECM_QT_DECLARE_LOGGING_CATEGORY_TEMPLATE_H "${CMAKE_CURRENT_LIST_DIR}/ECMQtDeclareLoggingCategory.h.in") +function(ecm_qt_export_logging_category) + set(options) + set(oneValueArgs IDENTIFIER CATEGORY_NAME DEFAULT_SEVERITY EXPORT DESCRIPTION) + set(multiValueArgs OLD_CATEGORY_NAMES) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unexpected arguments to ecm_qt_export_logging_category: ${ARG_UNPARSED_ARGUMENTS}") + endif() + if(NOT ARG_IDENTIFIER) + message(FATAL_ERROR "Missing IDENTIFIER argument for ecm_qt_export_logging_category") + endif() + if(NOT ARG_CATEGORY_NAME) + message(FATAL_ERROR "Missing CATEGORY_NAME argument for ecm_qt_export_logging_category") + endif() + if(NOT ARG_DEFAULT_SEVERITY) + set(ARG_DEFAULT_SEVERITY Info) + set(is_explicite_default_severity FALSE) + else() + set(acceptible_severities Debug Info Warning Critical Fatal) + list(FIND acceptible_severities "${ARG_DEFAULT_SEVERITY}" pos) + if (pos EQUAL -1) + message(FATAL_ERROR "Unknown DEFAULT_SEVERITY ${pos}") + endif() + set(is_explicite_default_severity TRUE) + endif() + if(NOT ARG_EXPORT) + message(FATAL_ERROR "Missing EXPORT argument for ecm_qt_export_logging_category.") + endif() + if(NOT ARG_DESCRIPTION) + message(FATAL_ERROR "Missing DESCRIPTION argument for ecm_qt_export_logging_category.") + endif() + + # note data in global properties + set(_propertyprefix "ECM_QT_LOGGING_CATEGORY_${ARG_EXPORT}") + set_property(GLOBAL APPEND PROPERTY "${_propertyprefix}_CATEGORIES" ${ARG_CATEGORY_NAME}) + set_property(GLOBAL PROPERTY "${_propertyprefix}_IDENTIFIER_${ARG_CATEGORY_NAME}" "${ARG_IDENTIFIER}") + set_property(GLOBAL PROPERTY "${_propertyprefix}_DESCRIPTION_${ARG_CATEGORY_NAME}" "${ARG_DESCRIPTION}") + set_property(GLOBAL PROPERTY "${_propertyprefix}_OLD_NAMES_${ARG_CATEGORY_NAME}" "${ARG_OLD_CATEGORY_NAMES}") + if (is_explicite_default_severity) + set_property(GLOBAL PROPERTY "${_propertyprefix}_DEFAULT_SEVERITY_${ARG_CATEGORY_NAME}" "${ARG_DEFAULT_SEVERITY}") + endif() +endfunction() + + function(ecm_qt_declare_logging_category sources_var) set(options) - set(oneValueArgs HEADER IDENTIFIER CATEGORY_NAME DEFAULT_SEVERITY) - set(multiValueArgs) + set(oneValueArgs HEADER IDENTIFIER CATEGORY_NAME DEFAULT_SEVERITY EXPORT DESCRIPTION) + set(multiValueArgs OLD_CATEGORY_NAMES) cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(ARG_UNPARSED_ARGUMENTS) @@ -83,12 +235,17 @@ endif() if(NOT ARG_DEFAULT_SEVERITY) set(ARG_DEFAULT_SEVERITY Info) + set(is_explicite_default_severity FALSE) else() set(acceptible_severities Debug Info Warning Critical Fatal) list(FIND acceptible_severities "${ARG_DEFAULT_SEVERITY}" pos) if (pos EQUAL -1) message(FATAL_ERROR "Unknown DEFAULT_SEVERITY ${pos}") endif() + set(is_explicite_default_severity TRUE) + endif() + if(ARG_EXPORT AND NOT ARG_DESCRIPTION) + message(FATAL_ERROR "Missing DESCRIPTION argument for ecm_qt_declare_logging_category.") endif() if (NOT IS_ABSOLUTE "${ARG_HEADER}") @@ -132,4 +289,125 @@ set(sources "${${sources_var}}") list(APPEND sources "${cpp_filename}") set(${sources_var} "${sources}" PARENT_SCOPE) + + # note data in global properties + if (ARG_EXPORT) + set(_default_severity) + if (is_explicite_default_severity) + set(_default_severity DEFAULT_SEVERITY ${ARG_DEFAULT_SEVERITY}) + endif() + set(_old_category_name) + if (ARG_OLD_CATEGORY_NAMES) + set(_old_category_names OLD_CATEGORY_NAMES ${ARG_OLD_CATEGORY_NAMES}) + endif() + ecm_qt_export_logging_category( + IDENTIFIER ${ARG_IDENTIFIER} + CATEGORY_NAME ${ARG_CATEGORY_NAME} + ${_old_category_names} + ${_default_severity} + EXPORT ${ARG_EXPORT} + DESCRIPTION "${ARG_DESCRIPTION}" + ) + endif() +endfunction() + + +function(ecm_qt_install_logging_categories) + set(options SORT) + set(oneValueArgs FILE EXPORT DESTINATION COMPONENT) + set(multiValueArgs) + + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT ARGS_EXPORT) + message(FATAL_ERROR "Missing EXPORT argument for ecm_qt_install_logging_categories") + endif() + + if(NOT ARGS_DESTINATION) + message(FATAL_ERROR "Missing DESTINATION argument for ecm_qt_install_logging_categories") + endif() + + if(NOT ARGS_FILE) + string(TOLOWER "${ARGS_EXPORT}.categories" ARGS_FILE) + endif() + + set(_propertyprefix "ECM_QT_LOGGING_CATEGORY_${ARGS_EXPORT}") + get_property(has_category GLOBAL PROPERTY "${_propertyprefix}_CATEGORIES" SET) + + if (NOT has_category) + message(FATAL_ERROR "${ARGS_EXPORT} is an unknown qt logging category export name.") + endif() + + get_property(_categories GLOBAL PROPERTY "${_propertyprefix}_CATEGORIES") + if (ARGS_SORT) + list(SORT _categories) + endif() + + set(_renamed_categories) + + # generate categories file + if (NOT IS_ABSOLUTE "${ARGS_FILE}") + set(ARGS_FILE "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_FILE}") + endif() + + file(WRITE ${ARGS_FILE} +"# KDebugSettings data file +# This file was generated by ecm_qt_install_logging_categories(). DO NOT EDIT! + +") + + foreach(_category IN LISTS _categories) + get_property(_description GLOBAL PROPERTY "${_propertyprefix}_DESCRIPTION_${_category}") + get_property(_identifier GLOBAL PROPERTY "${_propertyprefix}_IDENTIFIER_${_category}") + get_property(_default_severity GLOBAL PROPERTY "${_propertyprefix}_DEFAULT_SEVERITY_${_category}") + if (_default_severity) + string(TOUPPER "${_default_severity}" _default_severity) + set(_default_severity "DEFAULT_SEVERITY [${_default_severity}] ") # final space wanted + endif() + get_property(_old_category_names GLOBAL PROPERTY "${_propertyprefix}_OLD_NAMES_${_category}") + if (_old_category_names) + list(APPEND _renamed_categories ${_category}) + endif() + + # Format: + # lognamedescription(optional DEFAULT_SEVERITY [DEFAULT_CATEGORY] as WARNING/DEBUG/INFO/CRITICAL) optional IDENTIFIER [...]) + file(APPEND ${ARGS_FILE} "${_category} ${_description} ${_default_severity}IDENTIFIER [${_identifier}]\n") + endforeach() + + set(_renamed_cats_file) + if (_renamed_categories) + get_filename_component(_dir ${ARGS_FILE} DIRECTORY) + get_filename_component(_base_name ${ARGS_FILE} NAME_WLE) + set(_renamed_cats_file "${_dir}/${_base_name}.renamecategories") + file(WRITE ${_renamed_cats_file} +"# KDebugSettings data file +# This file was generated by ecm_qt_install_logging_categories(). DO NOT EDIT! + +") + + foreach(_category IN LISTS _renamed_categories) + get_property(_category_name_history GLOBAL PROPERTY "${_propertyprefix}_OLD_NAMES_${_category}") + + list(APPEND _category_name_history ${_category}) + list(GET _category_name_history 0 _old_category_name) + list(REMOVE_AT _category_name_history 0) + foreach(_category_name IN LISTS _category_name_history) + # Format: + # oldlognamenewlogname + file(APPEND ${_renamed_cats_file} "${_old_category_name} ${_category_name}\n") + set(_old_category_name ${_category_name}) + endforeach() + endforeach() + endif() + + # install files + set(_component_install) + if (ARGS_COMPONENT) + set(_component_install COMPONENT ${ARGS_COMPONENT}) + endif() + install( + FILES ${ARGS_FILE} ${_renamed_cats_file} + DESTINATION "${ARGS_DESTINATION}" + ${_component_install} + ) endfunction() diff --git a/tests/ECMQtDeclareLoggingCategoryTest/CMakeLists.txt b/tests/ECMQtDeclareLoggingCategoryTest/CMakeLists.txt --- a/tests/ECMQtDeclareLoggingCategoryTest/CMakeLists.txt +++ b/tests/ECMQtDeclareLoggingCategoryTest/CMakeLists.txt @@ -5,19 +5,45 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_DIR}) include(ECMQtDeclareLoggingCategory) +include(CMakeParseArguments) + +function (check_file) + set(options) + set(oneValueArgs GENERATED EXPECTED) + set(multiValueArgs) + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT EXISTS "${ARGS_GENERATED}") + message(FATAL_ERROR "${ARGS_GENERATED} was not generated") + endif() + file(READ "${ARGS_GENERATED}" generated_contents) + if (NOT EXISTS "${ARGS_EXPECTED}") + message(FATAL_ERROR "Original ${ARGS_EXPECTED} was not found") + endif() + file(READ "${ARGS_EXPECTED}" original_contents) + if (NOT "${generated_contents}" STREQUAL "${original_contents}") + message(FATAL_ERROR "${generated_file} contains '${generated_contents}' instead of '${original_contents}'") + endif() +endfunction() ecm_qt_declare_logging_category( sources HEADER "log1.h" IDENTIFIER "log1" CATEGORY_NAME "log.one" + OLD_CATEGORY_NAMES "log1old" + DESCRIPTION "log 1" + EXPORT LOG ) ecm_qt_declare_logging_category( sources HEADER "log2.h" IDENTIFIER "foo::bar::log2" CATEGORY_NAME "log.two" + DEFAULT_SEVERITY Info + DESCRIPTION "log 2" + EXPORT LOG ) ecm_qt_declare_logging_category( @@ -28,6 +54,15 @@ DEFAULT_SEVERITY Critical ) +ecm_qt_export_logging_category( + IDENTIFIER "log4" + CATEGORY_NAME "log.four" + OLD_CATEGORY_NAMES "logfouroldest" "log4old" + DEFAULT_SEVERITY Warning + EXPORT LOG + DESCRIPTION "log 4" +) + find_package(Qt5Core REQUIRED) add_executable(testmain testmain.cpp ${sources}) @@ -40,3 +75,18 @@ Qt5::Core ) +ecm_qt_install_logging_categories( + EXPORT LOG + FILE log.categories + DESTINATION "${CMAKE_BINARY_DIR}/dummyinstall" +) + +check_file( + GENERATED "${CMAKE_CURRENT_BINARY_DIR}/log.categories" + EXPECTED "${CMAKE_CURRENT_SOURCE_DIR}/log.categories" +) +check_file( + GENERATED "${CMAKE_CURRENT_BINARY_DIR}/log.renamecategories" + EXPECTED "${CMAKE_CURRENT_SOURCE_DIR}/log.renamecategories" +) + diff --git a/tests/ECMQtDeclareLoggingCategoryTest/log.categories b/tests/ECMQtDeclareLoggingCategoryTest/log.categories new file mode 100644 --- /dev/null +++ b/tests/ECMQtDeclareLoggingCategoryTest/log.categories @@ -0,0 +1,6 @@ +# KDebugSettings data file +# This file was generated by ecm_qt_install_logging_categories(). DO NOT EDIT! + +log.one log 1 IDENTIFIER [log1] +log.two log 2 DEFAULT_SEVERITY [INFO] IDENTIFIER [foo::bar::log2] +log.four log 4 DEFAULT_SEVERITY [WARNING] IDENTIFIER [log4] diff --git a/tests/ECMQtDeclareLoggingCategoryTest/log.renamecategories b/tests/ECMQtDeclareLoggingCategoryTest/log.renamecategories new file mode 100644 --- /dev/null +++ b/tests/ECMQtDeclareLoggingCategoryTest/log.renamecategories @@ -0,0 +1,6 @@ +# KDebugSettings data file +# This file was generated by ecm_qt_install_logging_categories(). DO NOT EDIT! + +log1old log.one +logfouroldest log4old +log4old log.four