Commit 6cc93b37 authored by Alex Turbov's avatar Alex Turbov Committed by Craig Scott

message(): Add support for log levels

Relates: #18943Co-Authored-By: Craig Scott's avatarCraig Scott <craig.scott@crascit.com>
parent 377d1b78
...@@ -116,6 +116,9 @@ _cmake() ...@@ -116,6 +116,9 @@ _cmake()
2>/dev/null )' -- "$quoted" ) ) 2>/dev/null )' -- "$quoted" ) )
return return
;; ;;
--loglevel)
COMPREPLY=( $(compgen -W 'error warning notice status verbose debug trace' -- $cur ) )
;;
--help-command) --help-command)
COMPREPLY=( $( compgen -W '$( cmake --help-command-list 2>/dev/null| COMPREPLY=( $( compgen -W '$( cmake --help-command-list 2>/dev/null|
grep -v "^cmake version " )' -- "$cur" ) ) grep -v "^cmake version " )' -- "$cur" ) )
......
...@@ -9,24 +9,56 @@ Display a message to the user. ...@@ -9,24 +9,56 @@ Display a message to the user.
The optional ``<mode>`` keyword determines the type of message: The optional ``<mode>`` keyword determines the type of message:
:: ``FATAL_ERROR``
CMake Error, stop processing and generation.
(none) = Important information
STATUS = Incidental information ``SEND_ERROR``
WARNING = CMake Warning, continue processing CMake Error, continue processing, but skip generation.
AUTHOR_WARNING = CMake Warning (dev), continue processing
SEND_ERROR = CMake Error, continue processing, ``WARNING``
but skip generation CMake Warning, continue processing.
FATAL_ERROR = CMake Error, stop processing and generation
DEPRECATION = CMake Deprecation Error or Warning if variable ``AUTHOR_WARNING``
CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED CMake Warning (dev), continue processing.
is enabled, respectively, else no message.
``DEPRECATION``
The CMake command-line tool displays STATUS messages on stdout and all CMake Deprecation Error or Warning if variable
other message types on stderr. The CMake GUI displays all messages in :variable:`CMAKE_ERROR_DEPRECATED` or :variable:`CMAKE_WARN_DEPRECATED`
its log area. The interactive dialogs (ccmake and CMakeSetup) show is enabled, respectively, else no message.
``STATUS`` messages one at a time on a status line and other messages in
interactive pop-up boxes. (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 CMake Warning and Error message text displays using a simple markup
language. Non-indented text is formatted in line-wrapped paragraphs language. Non-indented text is formatted in line-wrapped paragraphs
......
...@@ -200,6 +200,12 @@ Options ...@@ -200,6 +200,12 @@ Options
from the top of a binary tree for a CMake project it will dump from the top of a binary tree for a CMake project it will dump
additional information such as the cache, log files etc. 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`` ``--debug-trycompile``
Do not delete the :command:`try_compile` build tree. Do not delete the :command:`try_compile` build tree.
Only useful on one :command:`try_compile` at a time. Only useful on one :command:`try_compile` at a time.
......
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``.
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
#include "cmMessenger.h" #include "cmMessenger.h"
#include "cmRange.h" #include "cmRange.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
#include "cmake.h"
#include <cassert>
class cmExecutionStatus; class cmExecutionStatus;
...@@ -24,41 +27,80 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args, ...@@ -24,41 +27,80 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args,
MessageType type = MessageType::MESSAGE; MessageType type = MessageType::MESSAGE;
bool status = false; bool status = false;
bool fatal = false; bool fatal = false;
auto level = cmake::LogLevel::LOG_UNDEFINED;
if (*i == "SEND_ERROR") { if (*i == "SEND_ERROR") {
type = MessageType::FATAL_ERROR; type = MessageType::FATAL_ERROR;
level = cmake::LogLevel::LOG_ERROR;
++i; ++i;
} else if (*i == "FATAL_ERROR") { } else if (*i == "FATAL_ERROR") {
fatal = true; fatal = true;
type = MessageType::FATAL_ERROR; type = MessageType::FATAL_ERROR;
level = cmake::LogLevel::LOG_ERROR;
++i; ++i;
} else if (*i == "WARNING") { } else if (*i == "WARNING") {
type = MessageType::WARNING; type = MessageType::WARNING;
level = cmake::LogLevel::LOG_WARNING;
++i; ++i;
} else if (*i == "AUTHOR_WARNING") { } else if (*i == "AUTHOR_WARNING") {
if (this->Makefile->IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") && if (this->Makefile->IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) { !this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
fatal = true; fatal = true;
type = MessageType::AUTHOR_ERROR; type = MessageType::AUTHOR_ERROR;
level = cmake::LogLevel::LOG_ERROR;
} else if (!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) { } else if (!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
type = MessageType::AUTHOR_WARNING; type = MessageType::AUTHOR_WARNING;
level = cmake::LogLevel::LOG_WARNING;
} else { } else {
return true; return true;
} }
++i; ++i;
} else if (*i == "STATUS") { } else if (*i == "STATUS") {
status = true; 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; ++i;
} else if (*i == "DEPRECATION") { } else if (*i == "DEPRECATION") {
if (this->Makefile->IsOn("CMAKE_ERROR_DEPRECATED")) { if (this->Makefile->IsOn("CMAKE_ERROR_DEPRECATED")) {
fatal = true; fatal = true;
type = MessageType::DEPRECATION_ERROR; type = MessageType::DEPRECATION_ERROR;
level = cmake::LogLevel::LOG_ERROR;
} else if ((!this->Makefile->IsSet("CMAKE_WARN_DEPRECATED") || } else if ((!this->Makefile->IsSet("CMAKE_WARN_DEPRECATED") ||
this->Makefile->IsOn("CMAKE_WARN_DEPRECATED"))) { this->Makefile->IsOn("CMAKE_WARN_DEPRECATED"))) {
type = MessageType::DEPRECATION_WARNING; type = MessageType::DEPRECATION_WARNING;
level = cmake::LogLevel::LOG_WARNING;
} else { } else {
return true; return true;
} }
++i; ++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()); std::string message = cmJoin(cmMakeRange(i, args.end()), std::string());
......
...@@ -718,6 +718,14 @@ void cmake::SetArgs(const std::vector<std::string>& args) ...@@ -718,6 +718,14 @@ void cmake::SetArgs(const std::vector<std::string>& args)
} else if (arg.find("--debug-output", 0) == 0) { } else if (arg.find("--debug-output", 0) == 0) {
std::cout << "Running with debug output on.\n"; std::cout << "Running with debug output on.\n";
this->SetDebugOutputOn(true); 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) { } else if (arg.find("--trace-expand", 0) == 0) {
std::cout << "Running with expanded trace output on.\n"; std::cout << "Running with expanded trace output on.\n";
this->SetTrace(true); this->SetTrace(true);
...@@ -828,6 +836,25 @@ void cmake::SetArgs(const std::vector<std::string>& args) ...@@ -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) void cmake::SetDirectoriesFromFile(const char* arg)
{ {
// Check if the argument refers to a CMakeCache.txt or // Check if the argument refers to a CMakeCache.txt or
......
...@@ -96,6 +96,19 @@ public: ...@@ -96,6 +96,19 @@ public:
FIND_PACKAGE_MODE 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 struct GeneratorInfo
{ {
std::string name; std::string name;
...@@ -331,6 +344,11 @@ public: ...@@ -331,6 +344,11 @@ public:
*/ */
cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache; } 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. // Do we want debug output during the cmake run.
bool GetDebugOutput() { return this->DebugOutput; } bool GetDebugOutput() { return this->DebugOutput; }
void SetDebugOutputOn(bool b) { this->DebugOutput = b; } void SetDebugOutputOn(bool b) { this->DebugOutput = b; }
...@@ -524,6 +542,8 @@ private: ...@@ -524,6 +542,8 @@ private:
std::vector<std::string> TraceOnlyThisSources; std::vector<std::string> TraceOnlyThisSources;
LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
void UpdateConversionPathTable(); void UpdateConversionPathTable();
// Print a list of valid generators to stderr. // Print a list of valid generators to stderr.
......
...@@ -95,6 +95,8 @@ static const char* cmDocumentationOptions[][2] = { ...@@ -95,6 +95,8 @@ static const char* cmDocumentationOptions[][2] = {
"Generate graphviz of dependencies, see " "Generate graphviz of dependencies, see "
"CMakeGraphVizOptions.cmake for more." }, "CMakeGraphVizOptions.cmake for more." },
{ "--system-information [file]", "Dump information about this system." }, { "--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", { "--debug-trycompile",
"Do not delete the try_compile build tree. Only " "Do not delete the try_compile build tree. Only "
"useful on one try_compile at a time." }, "useful on one try_compile at a time." },
......
...@@ -10,3 +10,45 @@ run_cmake(warnmessage) ...@@ -10,3 +10,45 @@ run_cmake(warnmessage)
# separately # separately
run_cmake(errormessage_deprecated) run_cmake(errormessage_deprecated)
run_cmake(errormessage_dev) 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
)
# 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")
^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$
-- STATUS message
-- VERBOSE message
-- DEBUG message
^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$
CMake Error: Invalid level specified for --loglevel
^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$
^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$
^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$
-- STATUS message
-- VERBOSE message
-- DEBUG message
-- TRACE message
^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$
^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$
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment