cmake/Source/cmMessenger.cxx

241 lines
6.5 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmMessenger.h"
#include "cmDocumentationFormatter.h"
2021-09-14 00:13:48 +02:00
#include "cmMessageMetadata.h"
2020-02-01 23:06:01 +01:00
#include "cmStringAlgorithms.h"
2016-10-30 18:24:19 +01:00
#include "cmSystemTools.h"
2020-02-01 23:06:01 +01:00
#if !defined(CMAKE_BOOTSTRAP)
2018-08-09 18:06:22 +02:00
# include "cmsys/SystemInformation.hxx"
2016-10-30 18:24:19 +01:00
#endif
#include <sstream>
2022-03-29 21:10:50 +02:00
#include <utility>
2016-10-30 18:24:19 +01:00
2021-09-14 00:13:48 +02:00
#include "cmsys/Terminal.h"
2023-07-02 19:51:09 +02:00
#ifdef CMake_ENABLE_DEBUGGER
# include "cmDebuggerAdapter.h"
#endif
2019-11-11 23:01:05 +01:00
MessageType cmMessenger::ConvertMessageType(MessageType t) const
2016-10-30 18:24:19 +01:00
{
2019-11-11 23:01:05 +01:00
if (t == MessageType::AUTHOR_WARNING || t == MessageType::AUTHOR_ERROR) {
2023-07-02 19:51:09 +02:00
if (this->GetDevWarningsAsErrors()) {
return MessageType::AUTHOR_ERROR;
2016-10-30 18:24:19 +01:00
}
2023-07-02 19:51:09 +02:00
return MessageType::AUTHOR_WARNING;
}
if (t == MessageType::DEPRECATION_WARNING ||
t == MessageType::DEPRECATION_ERROR) {
if (this->GetDeprecatedWarningsAsErrors()) {
return MessageType::DEPRECATION_ERROR;
2016-10-30 18:24:19 +01:00
}
2023-07-02 19:51:09 +02:00
return MessageType::DEPRECATION_WARNING;
2016-10-30 18:24:19 +01:00
}
return t;
}
2019-11-11 23:01:05 +01:00
bool cmMessenger::IsMessageTypeVisible(MessageType t) const
2016-10-30 18:24:19 +01:00
{
2019-11-11 23:01:05 +01:00
if (t == MessageType::DEPRECATION_ERROR) {
2023-07-02 19:51:09 +02:00
return this->GetDeprecatedWarningsAsErrors();
}
if (t == MessageType::DEPRECATION_WARNING) {
return !this->GetSuppressDeprecatedWarnings();
}
if (t == MessageType::AUTHOR_ERROR) {
return this->GetDevWarningsAsErrors();
}
if (t == MessageType::AUTHOR_WARNING) {
return !this->GetSuppressDevWarnings();
2016-10-30 18:24:19 +01:00
}
2023-07-02 19:51:09 +02:00
return true;
2016-10-30 18:24:19 +01:00
}
2019-11-11 23:01:05 +01:00
static bool printMessagePreamble(MessageType t, std::ostream& msg)
2016-10-30 18:24:19 +01:00
{
// Construct the message header.
2019-11-11 23:01:05 +01:00
if (t == MessageType::FATAL_ERROR) {
2016-10-30 18:24:19 +01:00
msg << "CMake Error";
2019-11-11 23:01:05 +01:00
} else if (t == MessageType::INTERNAL_ERROR) {
2016-10-30 18:24:19 +01:00
msg << "CMake Internal Error (please report a bug)";
2019-11-11 23:01:05 +01:00
} else if (t == MessageType::LOG) {
2016-10-30 18:24:19 +01:00
msg << "CMake Debug Log";
2019-11-11 23:01:05 +01:00
} else if (t == MessageType::DEPRECATION_ERROR) {
2016-10-30 18:24:19 +01:00
msg << "CMake Deprecation Error";
2019-11-11 23:01:05 +01:00
} else if (t == MessageType::DEPRECATION_WARNING) {
2016-10-30 18:24:19 +01:00
msg << "CMake Deprecation Warning";
2019-11-11 23:01:05 +01:00
} else if (t == MessageType::AUTHOR_WARNING) {
2016-10-30 18:24:19 +01:00
msg << "CMake Warning (dev)";
2019-11-11 23:01:05 +01:00
} else if (t == MessageType::AUTHOR_ERROR) {
2016-10-30 18:24:19 +01:00
msg << "CMake Error (dev)";
} else {
msg << "CMake Warning";
}
return true;
}
2021-09-14 00:13:48 +02:00
static int getMessageColor(MessageType t)
{
switch (t) {
case MessageType::INTERNAL_ERROR:
case MessageType::FATAL_ERROR:
case MessageType::AUTHOR_ERROR:
return cmsysTerminal_Color_ForegroundRed;
case MessageType::AUTHOR_WARNING:
case MessageType::WARNING:
return cmsysTerminal_Color_ForegroundYellow;
default:
return cmsysTerminal_Color_Normal;
}
}
2022-03-29 21:10:50 +02:00
static void printMessageText(std::ostream& msg, std::string const& text)
2016-10-30 18:24:19 +01:00
{
msg << ":\n";
cmDocumentationFormatter formatter;
2023-05-23 16:38:00 +02:00
formatter.SetIndent(2u);
formatter.PrintFormatted(msg, text);
2016-10-30 18:24:19 +01:00
}
2022-03-29 21:10:50 +02:00
static void displayMessage(MessageType t, std::ostringstream& msg)
2016-10-30 18:24:19 +01:00
{
// Add a note about warning suppression.
2019-11-11 23:01:05 +01:00
if (t == MessageType::AUTHOR_WARNING) {
2016-10-30 18:24:19 +01:00
msg << "This warning is for project developers. Use -Wno-dev to suppress "
"it.";
2019-11-11 23:01:05 +01:00
} else if (t == MessageType::AUTHOR_ERROR) {
2016-10-30 18:24:19 +01:00
msg << "This error is for project developers. Use -Wno-error=dev to "
2020-02-01 23:06:01 +01:00
"suppress it.";
2016-10-30 18:24:19 +01:00
}
// Add a terminating blank line.
msg << "\n";
2020-02-01 23:06:01 +01:00
#if !defined(CMAKE_BOOTSTRAP)
2016-10-30 18:24:19 +01:00
// Add a C++ stack trace to internal errors.
2019-11-11 23:01:05 +01:00
if (t == MessageType::INTERNAL_ERROR) {
2016-10-30 18:24:19 +01:00
std::string stack = cmsys::SystemInformation::GetProgramStack(0, 0);
if (!stack.empty()) {
if (cmHasLiteralPrefix(stack, "WARNING:")) {
stack = "Note:" + stack.substr(8);
}
msg << stack << "\n";
}
}
#endif
// Output the message.
2021-09-14 00:13:48 +02:00
cmMessageMetadata md;
md.desiredColor = getMessageColor(t);
2019-11-11 23:01:05 +01:00
if (t == MessageType::FATAL_ERROR || t == MessageType::INTERNAL_ERROR ||
t == MessageType::DEPRECATION_ERROR || t == MessageType::AUTHOR_ERROR) {
2022-08-04 22:12:04 +02:00
cmSystemTools::SetErrorOccurred();
2021-09-14 00:13:48 +02:00
md.title = "Error";
cmSystemTools::Message(msg.str(), md);
2016-10-30 18:24:19 +01:00
} else {
2021-09-14 00:13:48 +02:00
md.title = "Warning";
cmSystemTools::Message(msg.str(), md);
2016-10-30 18:24:19 +01:00
}
}
2022-03-29 21:10:50 +02:00
namespace {
void PrintCallStack(std::ostream& out, cmListFileBacktrace bt,
cm::optional<std::string> const& topSource)
{
// The call stack exists only if we have at least two calls on top
// of the bottom.
if (bt.Empty()) {
return;
}
bt = bt.Pop();
if (bt.Empty()) {
return;
}
bool first = true;
for (; !bt.Empty(); bt = bt.Pop()) {
cmListFileContext lfc = bt.Top();
if (lfc.Name.empty() &&
lfc.Line != cmListFileContext::DeferPlaceholderLine) {
// Skip this whole-file scope. When we get here we already will
// have printed a more-specific context within the file.
continue;
}
if (first) {
first = false;
out << "Call Stack (most recent call first):\n";
}
if (topSource) {
lfc.FilePath = cmSystemTools::RelativeIfUnder(*topSource, lfc.FilePath);
}
out << " " << lfc << "\n";
}
}
}
2019-11-11 23:01:05 +01:00
void cmMessenger::IssueMessage(MessageType t, const std::string& text,
2016-10-30 18:24:19 +01:00
const cmListFileBacktrace& backtrace) const
{
bool force = false;
2022-03-29 21:10:50 +02:00
// override the message type, if needed, for warnings and errors
MessageType override = this->ConvertMessageType(t);
if (override != t) {
t = override;
force = true;
2016-10-30 18:24:19 +01:00
}
2022-03-29 21:10:50 +02:00
if (force || this->IsMessageTypeVisible(t)) {
this->DisplayMessage(t, text, backtrace);
2016-10-30 18:24:19 +01:00
}
}
2019-11-11 23:01:05 +01:00
void cmMessenger::DisplayMessage(MessageType t, const std::string& text,
2016-10-30 18:24:19 +01:00
const cmListFileBacktrace& backtrace) const
{
std::ostringstream msg;
if (!printMessagePreamble(t, msg)) {
return;
}
// Add the immediate context.
2022-03-29 21:10:50 +02:00
this->PrintBacktraceTitle(msg, backtrace);
2016-10-30 18:24:19 +01:00
printMessageText(msg, text);
// Add the rest of the context.
2022-03-29 21:10:50 +02:00
PrintCallStack(msg, backtrace, this->TopSource);
2016-10-30 18:24:19 +01:00
displayMessage(t, msg);
2023-07-02 19:51:09 +02:00
#ifdef CMake_ENABLE_DEBUGGER
if (DebuggerAdapter != nullptr) {
DebuggerAdapter->OnMessageOutput(t, msg.str());
}
#endif
2016-10-30 18:24:19 +01:00
}
2022-03-29 21:10:50 +02:00
void cmMessenger::PrintBacktraceTitle(std::ostream& out,
cmListFileBacktrace const& bt) const
{
// The title exists only if we have a call on top of the bottom.
if (bt.Empty()) {
return;
}
cmListFileContext lfc = bt.Top();
if (this->TopSource) {
lfc.FilePath =
cmSystemTools::RelativeIfUnder(*this->TopSource, lfc.FilePath);
}
out << (lfc.Line ? " at " : " in ") << lfc;
}
void cmMessenger::SetTopSource(cm::optional<std::string> topSource)
{
this->TopSource = std::move(topSource);
}