Просмотр исходного кода

message(): Add support for log levels

Relates: #18943
Co-Authored-By: Craig Scott <[email protected]>
Alex Turbov 6 лет назад
Родитель
Сommit
6cc93b370e

+ 3 - 0
Auxiliary/bash-completion/cmake

@@ -116,6 +116,9 @@ _cmake()
                 2>/dev/null )' -- "$quoted" ) )
             return
             ;;
+        --loglevel)
+            COMPREPLY=( $(compgen -W 'error warning notice status verbose debug trace' -- $cur ) )
+            ;;
         --help-command)
             COMPREPLY=( $( compgen -W '$( cmake --help-command-list 2>/dev/null|
                 grep -v "^cmake version " )' -- "$cur" ) )

+ 50 - 18
Help/command/message.rst

@@ -9,24 +9,56 @@ Display a message to the user.
 
 The optional ``<mode>`` keyword determines the type of message:
 
-::
-
-  (none)         = Important information
-  STATUS         = Incidental information
-  WARNING        = CMake Warning, continue processing
-  AUTHOR_WARNING = CMake Warning (dev), continue processing
-  SEND_ERROR     = CMake Error, continue processing,
-                                but skip generation
-  FATAL_ERROR    = CMake Error, stop processing and generation
-  DEPRECATION    = CMake Deprecation Error or Warning if variable
-                   CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED
-                   is enabled, respectively, else no message.
-
-The CMake command-line tool displays STATUS messages on stdout and all
-other message types on stderr.  The CMake GUI displays all messages in
-its log area.  The interactive dialogs (ccmake and CMakeSetup) show
-``STATUS`` messages one at a time on a status line and other messages in
-interactive pop-up boxes.
+``FATAL_ERROR``
+  CMake Error, stop processing and generation.
+
+``SEND_ERROR``
+  CMake Error, continue processing, but skip generation.
+
+``WARNING``
+  CMake Warning, continue processing.
+
+``AUTHOR_WARNING``
+  CMake Warning (dev), continue processing.
+
+``DEPRECATION``
+  CMake Deprecation Error or Warning if variable
+  :variable:`CMAKE_ERROR_DEPRECATED` or :variable:`CMAKE_WARN_DEPRECATED`
+  is enabled, respectively, else no message.
+
+(none) or ``NOTICE``
+  Important message printed to stderr to attract user's attention.
+
+``STATUS``
+  The main interesting messages that project users might be interested in.
+  Ideally these should be concise, no more than a single line, but still
+  informative.
+
+``VERBOSE``
+  Detailed informational messages intended for project users.  These messages
+  should provide additional details that won't be of interest in most cases,
+  but which may be useful to those building the project when they want deeper
+  insight into what's happening.
+
+``DEBUG``
+  Detailed informational messages intended for developers working on the
+  project itself as opposed to users who just want to build it.  These messages
+  will not typically be of interest to other users building the project and
+  will often be closely related to internal implementation details.
+
+``TRACE``
+  Fine-grained messages with very low-level implementation details.  Messages
+  using this log level would normally only be temporary and would expect to be
+  removed before releasing the project, packaging up the files, etc.
+
+The CMake command-line tool displays ``STATUS`` to ``TRACE`` messages on stdout
+with the message preceded by two hyphens and a space.  All other message types
+are sent to stderr and are not prefixed with hyphens.  The CMake GUI displays
+all messages in its log area.  The interactive dialogs (:manual:`ccmake(1)`
+and :manual:`cmake-gui(1)`) show ``STATUS`` to ``TRACE`` messages one at a
+time on a status line and other messages in interactive pop-up boxes.
+The ``--loglevel`` command-line option to each of these tools can be used to
+control which messages will be shown.
 
 CMake Warning and Error message text displays using a simple markup
 language.  Non-indented text is formatted in line-wrapped paragraphs

+ 6 - 0
Help/manual/cmake.1.rst

@@ -200,6 +200,12 @@ Options
  from the top of a binary tree for a CMake project it will dump
  additional information such as the cache, log files etc.
 
+``--loglevel=<error|warning|notice|status|verbose|debug|trace>``
+ Set the log level.
+
+ The :command:`message` command will only output messages of the specified
+ log level or higher.  The default log level is ``status``.
+
 ``--debug-trycompile``
  Do not delete the :command:`try_compile` build tree.
  Only useful on one :command:`try_compile` at a time.

+ 7 - 0
Help/release/dev/new-message-types-and-logging.rst

@@ -0,0 +1,7 @@
+new-message-types-and-logging
+-----------------------------
+
+* The :command:`message` command learned new types: ``NOTICE``, ``VERBOSE``,
+  ``DEBUG`` and ``TRACE``.
+
+* The :manual:`cmake(1)` command learned a new CLI option ``--loglevel``.

+ 42 - 0
Source/cmMessageCommand.cxx

@@ -8,6 +8,9 @@
 #include "cmMessenger.h"
 #include "cmRange.h"
 #include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cassert>
 
 class cmExecutionStatus;
 
@@ -24,41 +27,80 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args,
   MessageType type = MessageType::MESSAGE;
   bool status = false;
   bool fatal = false;
+  auto level = cmake::LogLevel::LOG_UNDEFINED;
   if (*i == "SEND_ERROR") {
     type = MessageType::FATAL_ERROR;
+    level = cmake::LogLevel::LOG_ERROR;
     ++i;
   } else if (*i == "FATAL_ERROR") {
     fatal = true;
     type = MessageType::FATAL_ERROR;
+    level = cmake::LogLevel::LOG_ERROR;
     ++i;
   } else if (*i == "WARNING") {
     type = MessageType::WARNING;
+    level = cmake::LogLevel::LOG_WARNING;
     ++i;
   } else if (*i == "AUTHOR_WARNING") {
     if (this->Makefile->IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
         !this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
       fatal = true;
       type = MessageType::AUTHOR_ERROR;
+      level = cmake::LogLevel::LOG_ERROR;
     } else if (!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
       type = MessageType::AUTHOR_WARNING;
+      level = cmake::LogLevel::LOG_WARNING;
     } else {
       return true;
     }
     ++i;
   } else if (*i == "STATUS") {
     status = true;
+    level = cmake::LogLevel::LOG_STATUS;
+    ++i;
+  } else if (*i == "VERBOSE") {
+    status = true;
+    level = cmake::LogLevel::LOG_VERBOSE;
+    ++i;
+  } else if (*i == "DEBUG") {
+    status = true;
+    level = cmake::LogLevel::LOG_DEBUG;
+    ++i;
+  } else if (*i == "TRACE") {
+    status = true;
+    level = cmake::LogLevel::LOG_TRACE;
     ++i;
   } else if (*i == "DEPRECATION") {
     if (this->Makefile->IsOn("CMAKE_ERROR_DEPRECATED")) {
       fatal = true;
       type = MessageType::DEPRECATION_ERROR;
+      level = cmake::LogLevel::LOG_ERROR;
     } else if ((!this->Makefile->IsSet("CMAKE_WARN_DEPRECATED") ||
                 this->Makefile->IsOn("CMAKE_WARN_DEPRECATED"))) {
       type = MessageType::DEPRECATION_WARNING;
+      level = cmake::LogLevel::LOG_WARNING;
     } else {
       return true;
     }
     ++i;
+  } else if (*i == "NOTICE") {
+    // `NOTICE` message type is going to be output to stderr
+    level = cmake::LogLevel::LOG_NOTICE;
+    ++i;
+  } else {
+    // Messages w/o any type are `NOTICE`s
+    level = cmake::LogLevel::LOG_NOTICE;
+  }
+  assert("Message log level expected to be set" &&
+         level != cmake::LogLevel::LOG_UNDEFINED);
+
+  auto desiredLevel = this->Makefile->GetCMakeInstance()->GetLogLevel();
+  assert("Expected a valid log level here" &&
+         desiredLevel != cmake::LogLevel::LOG_UNDEFINED);
+
+  if (desiredLevel < level) {
+    // Suppress the message
+    return true;
   }
 
   std::string message = cmJoin(cmMakeRange(i, args.end()), std::string());

+ 27 - 0
Source/cmake.cxx

@@ -718,6 +718,14 @@ void cmake::SetArgs(const std::vector<std::string>& args)
     } else if (arg.find("--debug-output", 0) == 0) {
       std::cout << "Running with debug output on.\n";
       this->SetDebugOutputOn(true);
+    } else if (arg.find("--loglevel=", 0) == 0) {
+      const auto logLevel =
+        StringToLogLevel(arg.substr(sizeof("--loglevel=") - 1));
+      if (logLevel == LogLevel::LOG_UNDEFINED) {
+        cmSystemTools::Error("Invalid level specified for --loglevel");
+        return;
+      }
+      this->SetLogLevel(logLevel);
     } else if (arg.find("--trace-expand", 0) == 0) {
       std::cout << "Running with expanded trace output on.\n";
       this->SetTrace(true);
@@ -828,6 +836,25 @@ void cmake::SetArgs(const std::vector<std::string>& args)
   }
 }
 
+cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr)
+{
+  using LevelsPair = std::pair<std::string, LogLevel>;
+  static const std::vector<LevelsPair> levels = {
+    { "error", LogLevel::LOG_ERROR },     { "warning", LogLevel::LOG_WARNING },
+    { "notice", LogLevel::LOG_NOTICE },   { "status", LogLevel::LOG_STATUS },
+    { "verbose", LogLevel::LOG_VERBOSE }, { "debug", LogLevel::LOG_DEBUG },
+    { "trace", LogLevel::LOG_TRACE }
+  };
+
+  const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr);
+
+  const auto it = std::find_if(levels.cbegin(), levels.cend(),
+                               [&levelStrLowCase](const LevelsPair& p) {
+                                 return p.first == levelStrLowCase;
+                               });
+  return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED;
+}
+
 void cmake::SetDirectoriesFromFile(const char* arg)
 {
   // Check if the argument refers to a CMakeCache.txt or

+ 20 - 0
Source/cmake.h

@@ -96,6 +96,19 @@ public:
     FIND_PACKAGE_MODE
   };
 
+  /** \brief Define log level constants. */
+  enum LogLevel
+  {
+    LOG_UNDEFINED,
+    LOG_ERROR,
+    LOG_WARNING,
+    LOG_NOTICE,
+    LOG_STATUS,
+    LOG_VERBOSE,
+    LOG_DEBUG,
+    LOG_TRACE
+  };
+
   struct GeneratorInfo
   {
     std::string name;
@@ -331,6 +344,11 @@ public:
    */
   cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache; }
 
+  // Get the selected log level for `message()` commands during the cmake run.
+  LogLevel GetLogLevel() const { return this->MessageLogLevel; }
+  void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; }
+  static LogLevel StringToLogLevel(const std::string& levelStr);
+
   // Do we want debug output during the cmake run.
   bool GetDebugOutput() { return this->DebugOutput; }
   void SetDebugOutputOn(bool b) { this->DebugOutput = b; }
@@ -524,6 +542,8 @@ private:
 
   std::vector<std::string> TraceOnlyThisSources;
 
+  LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
+
   void UpdateConversionPathTable();
 
   // Print a list of valid generators to stderr.

+ 2 - 0
Source/cmakemain.cxx

@@ -95,6 +95,8 @@ static const char* cmDocumentationOptions[][2] = {
     "Generate graphviz of dependencies, see "
     "CMakeGraphVizOptions.cmake for more." },
   { "--system-information [file]", "Dump information about this system." },
+  { "--loglevel=<error|warn|notice|status|verbose|debug|trace>",
+    "Set the verbosity of messages from CMake files." },
   { "--debug-trycompile",
     "Do not delete the try_compile build tree. Only "
     "useful on one try_compile at a time." },

+ 42 - 0
Tests/RunCMake/message/RunCMakeTest.cmake

@@ -10,3 +10,45 @@ run_cmake(warnmessage)
 # separately
 run_cmake(errormessage_deprecated)
 run_cmake(errormessage_dev)
+
+run_cmake_command(
+    message-loglevel-invalid
+    ${CMAKE_COMMAND} --loglevel=blah -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )
+
+# Checking various combinations of `message(...)` and log levels `WARNING` to `TRACE`
+# - no CLI option -> `WARNING` to `STATUS` output
+run_cmake_command(
+    message-loglevel-default
+    ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )
+# - Only `WARNING` output
+run_cmake_command(
+    message-loglevel-warning
+    ${CMAKE_COMMAND} --loglevel=warning -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )
+# - Only `WARNING` and `NOTICE` output
+run_cmake_command(
+    message-loglevel-notice
+    ${CMAKE_COMMAND} --loglevel=notice -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )
+# - `WARNING` to `STATUS` output
+run_cmake_command(
+    message-loglevel-status
+    ${CMAKE_COMMAND} --loglevel=status -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )
+# - `WARNING` to `VERBOSE` output
+run_cmake_command(
+    message-loglevel-verbose
+    ${CMAKE_COMMAND} --loglevel=verbose -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )
+# - `WARNING` to `DEBUG` output
+run_cmake_command(
+    message-loglevel-debug
+    ${CMAKE_COMMAND} --loglevel=debug -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )
+# - `WARNING` to `TRACE` output
+run_cmake_command(
+    message-loglevel-trace
+    ${CMAKE_COMMAND} --loglevel=trace -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )

+ 10 - 0
Tests/RunCMake/message/message-all-loglevels.cmake

@@ -0,0 +1,10 @@
+# Produce a message for everything except FATAL_ERROR and SEND_ERROR
+message(DEPRECATION "Deprecation warning")
+message(AUTHOR_WARNING "Author warning message")
+message(WARNING "Warning message")
+message("Default NOTICE message")
+message(NOTICE "NOTICE message")
+message(STATUS "STATUS message")
+message(VERBOSE "VERBOSE message")
+message(DEBUG "DEBUG message")
+message(TRACE "TRACE message")

+ 12 - 0
Tests/RunCMake/message/message-loglevel-debug-stderr.txt

@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+  Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+  Author warning message
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+  Warning message
++
+Default NOTICE message
+NOTICE message$

+ 3 - 0
Tests/RunCMake/message/message-loglevel-debug-stdout.txt

@@ -0,0 +1,3 @@
+-- STATUS message
+-- VERBOSE message
+-- DEBUG message

+ 12 - 0
Tests/RunCMake/message/message-loglevel-default-stderr.txt

@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+  Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+  Author warning message
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+  Warning message
++
+Default NOTICE message
+NOTICE message$

+ 1 - 0
Tests/RunCMake/message/message-loglevel-default-stdout.txt

@@ -0,0 +1 @@
+-- STATUS message

+ 1 - 0
Tests/RunCMake/message/message-loglevel-invalid-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/message/message-loglevel-invalid-stderr.txt

@@ -0,0 +1 @@
+CMake Error: Invalid level specified for --loglevel

+ 12 - 0
Tests/RunCMake/message/message-loglevel-notice-stderr.txt

@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+  Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+  Author warning message
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+  Warning message
++
+Default NOTICE message
+NOTICE message$

+ 12 - 0
Tests/RunCMake/message/message-loglevel-status-stderr.txt

@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+  Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+  Author warning message
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+  Warning message
++
+Default NOTICE message
+NOTICE message$

+ 1 - 0
Tests/RunCMake/message/message-loglevel-status-stdout.txt

@@ -0,0 +1 @@
+-- STATUS message

+ 12 - 0
Tests/RunCMake/message/message-loglevel-trace-stderr.txt

@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+  Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+  Author warning message
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+  Warning message
++
+Default NOTICE message
+NOTICE message$

+ 4 - 0
Tests/RunCMake/message/message-loglevel-trace-stdout.txt

@@ -0,0 +1,4 @@
+-- STATUS message
+-- VERBOSE message
+-- DEBUG message
+-- TRACE message

+ 12 - 0
Tests/RunCMake/message/message-loglevel-verbose-stderr.txt

@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+  Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+  Author warning message
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+  Warning message
++
+Default NOTICE message
+NOTICE message$

+ 2 - 0
Tests/RunCMake/message/message-loglevel-verbose-stdout.txt

@@ -0,0 +1,2 @@
+-- STATUS message
+-- VERBOSE message

+ 9 - 0
Tests/RunCMake/message/message-loglevel-warning-stderr.txt

@@ -0,0 +1,9 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+  Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+  Author warning message
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+  Warning message$