From 23bbac941a94391548b57303f9ab371fa5a82b96 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Fri, 24 Jun 2022 15:44:12 +0200 Subject: Add cmake_language(GET_MESSAGE_LOG_LEVEL) sub command The new sub-command writes a string representation of the current log level to the output variable given to the sub-command. Given that the log-level might be set either via the --log-level command line option or via the CMAKE_MESSAGE_LOG_LEVEL cache / regular variables, the priority for each of the log level sources is as follows, with the first one being the highest: 1) --log-level 2) CMAKE_MESSAGE_LOG_LEVEL regular variable 3) CMAKE_MESSAGE_LOG_LEVEL cache variable 4) default log level (STATUS) Fixes: #23572 --- Help/command/cmake_language.rst | 26 ++++++++++ Help/manual/cmake.1.rst | 5 ++ .../dev/cmake_language_GET_MESSAGE_LOG_LEVEL.rst | 6 +++ Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst | 5 ++ Source/cmCMakeLanguageCommand.cxx | 27 ++++++++++ Source/cmMakefile.cxx | 23 +++++++++ Source/cmMakefile.h | 1 + Source/cmMessageCommand.cxx | 13 +---- Source/cmake.cxx | 51 ++++++++++++++----- Source/cmake.h | 3 +- Tests/RunCMake/cmake_language/RunCMakeTest.cmake | 58 ++++++++++++++++++++++ .../cmake_language/get_message_log_level.cmake | 5 ++ .../get_message_log_level_cache-stdout.txt | 1 + .../get_message_log_level_cli-stdout.txt | 1 + .../get_message_log_level_cli_and_cache-stdout.txt | 1 + .../get_message_log_level_cli_and_var-stdout.txt | 1 + .../get_message_log_level_none-stdout.txt | 1 + .../get_message_log_level_var-stdout.txt | 1 + .../get_message_log_level_var_and_cache-stdout.txt | 1 + 19 files changed, 205 insertions(+), 25 deletions(-) create mode 100644 Help/release/dev/cmake_language_GET_MESSAGE_LOG_LEVEL.rst create mode 100644 Tests/RunCMake/cmake_language/get_message_log_level.cmake create mode 100644 Tests/RunCMake/cmake_language/get_message_log_level_cache-stdout.txt create mode 100644 Tests/RunCMake/cmake_language/get_message_log_level_cli-stdout.txt create mode 100644 Tests/RunCMake/cmake_language/get_message_log_level_cli_and_cache-stdout.txt create mode 100644 Tests/RunCMake/cmake_language/get_message_log_level_cli_and_var-stdout.txt create mode 100644 Tests/RunCMake/cmake_language/get_message_log_level_none-stdout.txt create mode 100644 Tests/RunCMake/cmake_language/get_message_log_level_var-stdout.txt create mode 100644 Tests/RunCMake/cmake_language/get_message_log_level_var_and_cache-stdout.txt diff --git a/Help/command/cmake_language.rst b/Help/command/cmake_language.rst index cb8d60b..377e42d 100644 --- a/Help/command/cmake_language.rst +++ b/Help/command/cmake_language.rst @@ -14,6 +14,7 @@ Synopsis cmake_language(`EVAL`_ CODE ...) cmake_language(`DEFER`_ ... CALL [...]) cmake_language(`SET_DEPENDENCY_PROVIDER`_ SUPPORTED_METHODS ...) + cmake_language(`GET_MESSAGE_LOG_LEVEL`_ ) Introduction ^^^^^^^^^^^^ @@ -491,3 +492,28 @@ calling the provider command recursively for the same dependency. SET_DEPENDENCY_PROVIDER mycomp_provide_dependency SUPPORTED_METHODS FIND_PACKAGE ) + +Getting current message log level +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.25 + +.. _GET_MESSAGE_LOG_LEVEL: +.. _query_message_log_level: + +.. code-block:: cmake + + cmake_language(GET_MESSAGE_LOG_LEVEL ) + +Writes the current :command:`message` logging level +into the given ````. + +See :command:`message` for the possible logging levels. + +The current message logging level can be set either using the ``--log-level`` +command line option of the :manual:`cmake(1)` program or using +the :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable. + +If both the command line option and the variable are set, the command line +option takes precedence. If neither are set, the default logging level +is returned. diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 38105dd..2726f13 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -249,6 +249,11 @@ Options For backward compatibility reasons, ``--loglevel`` is also accepted as a synonym for this option. + .. versionadded:: 3.25 + See the :command:`cmake_language` + :ref:`cmake_language ` command for a way to query + the current message logging level. + ``--log-context`` Enable the :command:`message` command outputting context attached to each message. diff --git a/Help/release/dev/cmake_language_GET_MESSAGE_LOG_LEVEL.rst b/Help/release/dev/cmake_language_GET_MESSAGE_LOG_LEVEL.rst new file mode 100644 index 0000000..6e99a05 --- /dev/null +++ b/Help/release/dev/cmake_language_GET_MESSAGE_LOG_LEVEL.rst @@ -0,0 +1,6 @@ +cmake-language_GET_MESSAGE_LOG_LEVEL +------------------------------------ + +* The :command:`cmake_language` command gained a new + ``GET_MESSAGE_LOG_LEVEL`` sub-command. It can be used to + query the current message logging level. diff --git a/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst b/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst index 3b45d1d..54ea6a4 100644 --- a/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst +++ b/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst @@ -15,3 +15,8 @@ subsequent CMake runs will continue to use the chosen log level. Projects should not set this variable, it is intended for users so that they may control the log level according to their own needs. + +.. versionadded:: 3.25 + See the :command:`cmake_language` + :ref:`cmake_language ` command for a way to query + the current message logging level. diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index a2aaa2a..287f45b 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -19,10 +19,12 @@ #include "cmGlobalGenerator.h" #include "cmListFileCache.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmRange.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmake.h" namespace { @@ -303,6 +305,27 @@ bool cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER( return true; } + +bool cmCMakeLanguageCommandGET_MESSAGE_LOG_LEVEL( + std::vector const& args, cmExecutionStatus& status) +{ + cmMakefile& makefile = status.GetMakefile(); + std::vector expandedArgs; + makefile.ExpandArguments(args, expandedArgs); + + if (args.size() < 2 || expandedArgs.size() > 2) { + return FatalError( + status, + "sub-command GET_MESSAGE_LOG_LEVEL expects exactly one argument"); + } + + Message::LogLevel logLevel = makefile.GetCurrentLogLevel(); + std::string outputValue = cmake::LogLevelToString(logLevel); + + const std::string& outputVariable = expandedArgs[1]; + makefile.AddDefinition(outputVariable, outputValue); + return true; +} } bool cmCMakeLanguageCommand(std::vector const& args, @@ -451,5 +474,9 @@ bool cmCMakeLanguageCommand(std::vector const& args, return cmCMakeLanguageCommandEVAL(args, status); } + if (expArgs[expArg] == "GET_MESSAGE_LOG_LEVEL") { + return cmCMakeLanguageCommandGET_MESSAGE_LOG_LEVEL(args, status); + } + return FatalError(status, "called with unknown meta-operation"); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 97a3db9..62ea427 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -149,6 +149,29 @@ void cmMakefile::IssueMessage(MessageType t, std::string const& text) const this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace); } +Message::LogLevel cmMakefile::GetCurrentLogLevel() const +{ + const cmake* cmakeInstance = this->GetCMakeInstance(); + + const Message::LogLevel logLevelCliOrDefault = cmakeInstance->GetLogLevel(); + assert("Expected a valid log level here" && + logLevelCliOrDefault != Message::LogLevel::LOG_UNDEFINED); + + Message::LogLevel result = logLevelCliOrDefault; + + // If the log-level was set via the command line option, it takes precedence + // over the CMAKE_MESSAGE_LOG_LEVEL variable. + if (!cmakeInstance->WasLogLevelSetViaCLI()) { + const Message::LogLevel logLevelFromVar = cmake::StringToLogLevel( + this->GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL")); + if (logLevelFromVar != Message::LogLevel::LOG_UNDEFINED) { + result = logLevelFromVar; + } + } + + return result; +} + bool cmMakefile::CheckCMP0037(std::string const& targetName, cmStateEnums::TargetType targetType) const { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index e7b9716..df40c82 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -925,6 +925,7 @@ public: }; void IssueMessage(MessageType t, std::string const& text) const; + Message::LogLevel GetCurrentLogLevel() const; /** Set whether or not to report a CMP0000 violation. */ void SetCheckCMP0000(bool b) { this->CheckCMP0000 = b; } diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index 9628124..fa29ec9 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -157,18 +157,7 @@ bool cmMessageCommand(std::vector const& args, assert("Message log level expected to be set" && level != Message::LogLevel::LOG_UNDEFINED); - auto desiredLevel = mf.GetCMakeInstance()->GetLogLevel(); - assert("Expected a valid log level here" && - desiredLevel != Message::LogLevel::LOG_UNDEFINED); - - // Command line option takes precedence over the cache variable - if (!mf.GetCMakeInstance()->WasLogLevelSetViaCLI()) { - const auto desiredLevelFromCache = - cmake::StringToLogLevel(mf.GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL")); - if (desiredLevelFromCache != Message::LogLevel::LOG_UNDEFINED) { - desiredLevel = desiredLevelFromCache; - } - } + Message::LogLevel desiredLevel = mf.GetCurrentLogLevel(); if (desiredLevel < level) { // Suppress the message diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 026c3d4..efb2520 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -3,6 +3,7 @@ #include "cmake.h" #include +#include #include #include #include @@ -1402,21 +1403,32 @@ void cmake::SetArgs(const std::vector& args) #endif } -Message::LogLevel cmake::StringToLogLevel(const std::string& levelStr) -{ - using LevelsPair = std::pair; - static const std::vector levels = { - { "error", Message::LogLevel::LOG_ERROR }, - { "warning", Message::LogLevel::LOG_WARNING }, - { "notice", Message::LogLevel::LOG_NOTICE }, - { "status", Message::LogLevel::LOG_STATUS }, - { "verbose", Message::LogLevel::LOG_VERBOSE }, - { "debug", Message::LogLevel::LOG_DEBUG }, - { "trace", Message::LogLevel::LOG_TRACE } +namespace { +using LevelsPair = std::pair; +using LevelsPairArray = std::array; +const LevelsPairArray& getStringToLogLevelPairs() +{ + static const LevelsPairArray levels = { + { { "error", Message::LogLevel::LOG_ERROR }, + { "warning", Message::LogLevel::LOG_WARNING }, + { "notice", Message::LogLevel::LOG_NOTICE }, + { "status", Message::LogLevel::LOG_STATUS }, + { "verbose", Message::LogLevel::LOG_VERBOSE }, + { "debug", Message::LogLevel::LOG_DEBUG }, + { "trace", Message::LogLevel::LOG_TRACE } } }; + return levels; +} +} // namespace + +Message::LogLevel cmake::StringToLogLevel(cm::string_view levelStr) +{ + const LevelsPairArray& levels = getStringToLogLevelPairs(); - const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr); + const auto levelStrLowCase = + cmSystemTools::LowerCase(std::string{ levelStr }); + // NOLINTNEXTLINE(readability-qualified-auto) const auto it = std::find_if(levels.cbegin(), levels.cend(), [&levelStrLowCase](const LevelsPair& p) { return p.first == levelStrLowCase; @@ -1424,6 +1436,21 @@ Message::LogLevel cmake::StringToLogLevel(const std::string& levelStr) return (it != levels.cend()) ? it->second : Message::LogLevel::LOG_UNDEFINED; } +std::string cmake::LogLevelToString(Message::LogLevel level) +{ + const LevelsPairArray& levels = getStringToLogLevelPairs(); + + // NOLINTNEXTLINE(readability-qualified-auto) + const auto it = + std::find_if(levels.cbegin(), levels.cend(), + [&level](const LevelsPair& p) { return p.second == level; }); + const cm::string_view levelStrLowerCase = + (it != levels.cend()) ? it->first : "undefined"; + std::string levelStrUpperCase = + cmSystemTools::UpperCase(std::string{ levelStrLowerCase }); + return levelStrUpperCase; +} + cmake::TraceFormat cmake::StringToTraceFormat(const std::string& traceStr) { using TracePair = std::pair; diff --git a/Source/cmake.h b/Source/cmake.h index 9d3348d..a631647 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -458,7 +458,8 @@ public: //! Get the selected log level for `message()` commands during the cmake run. Message::LogLevel GetLogLevel() const { return this->MessageLogLevel; } void SetLogLevel(Message::LogLevel level) { this->MessageLogLevel = level; } - static Message::LogLevel StringToLogLevel(const std::string& levelStr); + static Message::LogLevel StringToLogLevel(cm::string_view levelStr); + static std::string LogLevelToString(Message::LogLevel level); static TraceFormat StringToTraceFormat(const std::string& levelStr); bool HasCheckInProgress() const diff --git a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake index 6480b2e..03a15fc 100644 --- a/Tests/RunCMake/cmake_language/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_language/RunCMakeTest.cmake @@ -82,3 +82,61 @@ run_cmake(defer_get_call_id_var) run_cmake(defer_missing_arg) run_cmake(defer_missing_call) run_cmake(defer_unknown_option) + +# Default log level +run_cmake_command( + get_message_log_level_none + ${CMAKE_COMMAND} + -P ${RunCMake_SOURCE_DIR}/get_message_log_level.cmake + ) + +# Log level from cache +run_cmake_command( + get_message_log_level_cache + ${CMAKE_COMMAND} + -DCMAKE_MESSAGE_LOG_LEVEL=TRACE + -P ${RunCMake_SOURCE_DIR}/get_message_log_level.cmake + ) + +# Log level from regular variable +run_cmake_command( + get_message_log_level_var + ${CMAKE_COMMAND} + -DNEW_LOG_LEVEL=TRACE + -P ${RunCMake_SOURCE_DIR}/get_message_log_level.cmake + ) + +# Log level from command line +run_cmake_command( + get_message_log_level_cli + ${CMAKE_COMMAND} + --log-level=DEBUG + -P ${RunCMake_SOURCE_DIR}/get_message_log_level.cmake + ) + +# Log level from command line, it has higher priority over a cache variable +run_cmake_command( + get_message_log_level_cli_and_cache + ${CMAKE_COMMAND} + --log-level=DEBUG + -DCMAKE_MESSAGE_LOG_LEVEL=TRACE + -P ${RunCMake_SOURCE_DIR}/get_message_log_level.cmake + ) + +# Log level from command line, it has higher priority over a regular variable +run_cmake_command( + get_message_log_level_cli_and_var + ${CMAKE_COMMAND} + --log-level=DEBUG + -DNEW_LOG_LEVEL=TRACE + -P ${RunCMake_SOURCE_DIR}/get_message_log_level.cmake + ) + +# Log level from variable, it has higher priority over a cache variable +run_cmake_command( + get_message_log_level_var_and_cache + ${CMAKE_COMMAND} + -DNEW_LOG_LEVEL=DEBUG + -DCMAKE_MESSAGE_LOG_LEVEL=TRACE + -P ${RunCMake_SOURCE_DIR}/get_message_log_level.cmake + ) diff --git a/Tests/RunCMake/cmake_language/get_message_log_level.cmake b/Tests/RunCMake/cmake_language/get_message_log_level.cmake new file mode 100644 index 0000000..1740c1f --- /dev/null +++ b/Tests/RunCMake/cmake_language/get_message_log_level.cmake @@ -0,0 +1,5 @@ +if(NEW_LOG_LEVEL) + set(CMAKE_MESSAGE_LOG_LEVEL "${NEW_LOG_LEVEL}") +endif() +cmake_language(GET_MESSAGE_LOG_LEVEL log_level) +message(STATUS "log level is: ${log_level}") diff --git a/Tests/RunCMake/cmake_language/get_message_log_level_cache-stdout.txt b/Tests/RunCMake/cmake_language/get_message_log_level_cache-stdout.txt new file mode 100644 index 0000000..cf1cd7b --- /dev/null +++ b/Tests/RunCMake/cmake_language/get_message_log_level_cache-stdout.txt @@ -0,0 +1 @@ +log level is: TRACE diff --git a/Tests/RunCMake/cmake_language/get_message_log_level_cli-stdout.txt b/Tests/RunCMake/cmake_language/get_message_log_level_cli-stdout.txt new file mode 100644 index 0000000..4d6e1eb --- /dev/null +++ b/Tests/RunCMake/cmake_language/get_message_log_level_cli-stdout.txt @@ -0,0 +1 @@ +log level is: DEBUG diff --git a/Tests/RunCMake/cmake_language/get_message_log_level_cli_and_cache-stdout.txt b/Tests/RunCMake/cmake_language/get_message_log_level_cli_and_cache-stdout.txt new file mode 100644 index 0000000..4d6e1eb --- /dev/null +++ b/Tests/RunCMake/cmake_language/get_message_log_level_cli_and_cache-stdout.txt @@ -0,0 +1 @@ +log level is: DEBUG diff --git a/Tests/RunCMake/cmake_language/get_message_log_level_cli_and_var-stdout.txt b/Tests/RunCMake/cmake_language/get_message_log_level_cli_and_var-stdout.txt new file mode 100644 index 0000000..4d6e1eb --- /dev/null +++ b/Tests/RunCMake/cmake_language/get_message_log_level_cli_and_var-stdout.txt @@ -0,0 +1 @@ +log level is: DEBUG diff --git a/Tests/RunCMake/cmake_language/get_message_log_level_none-stdout.txt b/Tests/RunCMake/cmake_language/get_message_log_level_none-stdout.txt new file mode 100644 index 0000000..92ffd34 --- /dev/null +++ b/Tests/RunCMake/cmake_language/get_message_log_level_none-stdout.txt @@ -0,0 +1 @@ +log level is: STATUS diff --git a/Tests/RunCMake/cmake_language/get_message_log_level_var-stdout.txt b/Tests/RunCMake/cmake_language/get_message_log_level_var-stdout.txt new file mode 100644 index 0000000..cf1cd7b --- /dev/null +++ b/Tests/RunCMake/cmake_language/get_message_log_level_var-stdout.txt @@ -0,0 +1 @@ +log level is: TRACE diff --git a/Tests/RunCMake/cmake_language/get_message_log_level_var_and_cache-stdout.txt b/Tests/RunCMake/cmake_language/get_message_log_level_var_and_cache-stdout.txt new file mode 100644 index 0000000..4d6e1eb --- /dev/null +++ b/Tests/RunCMake/cmake_language/get_message_log_level_var_and_cache-stdout.txt @@ -0,0 +1 @@ +log level is: DEBUG -- cgit v0.12