mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00

The file API code used unsigned long to hold the major version in most places, but not all. Some places used unsigned int, and an important one of those is the cmFileApi::BuildVersion() function. As a result, it has never been safe for a large value not representable by an unsigned int to be used in these variables. Convert all of the file API version number variables and function arguments to use unsigned int consistently. This avoids any size mismatch warnings when passing values around. They also don't need to be unsigned long, as we never expect version numbers to be anything even close to what an unsigned int cannot represent.
248 lines
7.0 KiB
C++
248 lines
7.0 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
#include "cmMessageCommand.h"
|
|
|
|
#include <cassert>
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include <cm/string_view>
|
|
#include <cmext/string_view>
|
|
|
|
#include "cmConfigureLog.h"
|
|
#include "cmExecutionStatus.h"
|
|
#include "cmList.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmMessageType.h"
|
|
#include "cmMessenger.h"
|
|
#include "cmRange.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmake.h"
|
|
|
|
#ifdef CMake_ENABLE_DEBUGGER
|
|
# include "cmDebuggerAdapter.h"
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
std::string IndentText(std::string text, cmMakefile& mf)
|
|
{
|
|
auto indent =
|
|
cmList{ mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT") }.join("");
|
|
|
|
auto const showContext = mf.GetCMakeInstance()->GetShowLogContext() ||
|
|
mf.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW");
|
|
if (showContext) {
|
|
auto context =
|
|
cmList{ mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT") }.join(".");
|
|
if (!context.empty()) {
|
|
indent.insert(0u, cmStrCat("["_s, context, "] "_s));
|
|
}
|
|
}
|
|
|
|
if (!indent.empty()) {
|
|
cmSystemTools::ReplaceString(text, "\n", "\n" + indent);
|
|
text.insert(0u, indent);
|
|
}
|
|
return text;
|
|
}
|
|
|
|
void ReportCheckResult(cm::string_view what, std::string result,
|
|
cmMakefile& mf)
|
|
{
|
|
if (mf.GetCMakeInstance()->HasCheckInProgress()) {
|
|
auto text = mf.GetCMakeInstance()->GetTopCheckInProgressMessage() + " - " +
|
|
std::move(result);
|
|
mf.DisplayStatus(IndentText(std::move(text), mf), -1);
|
|
} else {
|
|
mf.GetMessenger()->DisplayMessage(
|
|
MessageType::AUTHOR_WARNING,
|
|
cmStrCat("Ignored "_s, what, " without CHECK_START"_s),
|
|
mf.GetBacktrace());
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
#ifndef CMAKE_BOOTSTRAP
|
|
void WriteMessageEvent(cmConfigureLog& log, cmMakefile const& mf,
|
|
std::string const& message)
|
|
{
|
|
// Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
|
|
static std::vector<unsigned int> const LogVersionsWithMessageV1{ 1 };
|
|
|
|
if (log.IsAnyLogVersionEnabled(LogVersionsWithMessageV1)) {
|
|
log.BeginEvent("message-v1", mf);
|
|
log.WriteLiteralTextBlock("message"_s, message);
|
|
log.EndEvent();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
// cmLibraryCommand
|
|
bool cmMessageCommand(std::vector<std::string> const& args,
|
|
cmExecutionStatus& status)
|
|
{
|
|
if (args.empty()) {
|
|
status.SetError("called with incorrect number of arguments");
|
|
return false;
|
|
}
|
|
|
|
auto& mf = status.GetMakefile();
|
|
|
|
auto i = args.cbegin();
|
|
|
|
auto type = MessageType::MESSAGE;
|
|
auto fatal = false;
|
|
auto level = Message::LogLevel::LOG_UNDEFINED;
|
|
auto checkingType = Message::CheckType::UNDEFINED;
|
|
if (*i == "SEND_ERROR") {
|
|
type = MessageType::FATAL_ERROR;
|
|
level = Message::LogLevel::LOG_ERROR;
|
|
++i;
|
|
} else if (*i == "FATAL_ERROR") {
|
|
fatal = true;
|
|
type = MessageType::FATAL_ERROR;
|
|
level = Message::LogLevel::LOG_ERROR;
|
|
++i;
|
|
} else if (*i == "WARNING") {
|
|
type = MessageType::WARNING;
|
|
level = Message::LogLevel::LOG_WARNING;
|
|
++i;
|
|
} else if (*i == "AUTHOR_WARNING") {
|
|
if (mf.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
|
|
!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
|
|
fatal = true;
|
|
type = MessageType::AUTHOR_ERROR;
|
|
level = Message::LogLevel::LOG_ERROR;
|
|
} else if (!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
|
|
type = MessageType::AUTHOR_WARNING;
|
|
level = Message::LogLevel::LOG_WARNING;
|
|
} else {
|
|
return true;
|
|
}
|
|
++i;
|
|
} else if (*i == "CHECK_START") {
|
|
level = Message::LogLevel::LOG_STATUS;
|
|
checkingType = Message::CheckType::CHECK_START;
|
|
++i;
|
|
} else if (*i == "CHECK_PASS") {
|
|
level = Message::LogLevel::LOG_STATUS;
|
|
checkingType = Message::CheckType::CHECK_PASS;
|
|
++i;
|
|
} else if (*i == "CHECK_FAIL") {
|
|
level = Message::LogLevel::LOG_STATUS;
|
|
checkingType = Message::CheckType::CHECK_FAIL;
|
|
++i;
|
|
} else if (*i == "CONFIGURE_LOG") {
|
|
#ifndef CMAKE_BOOTSTRAP
|
|
if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) {
|
|
++i;
|
|
WriteMessageEvent(*log, mf, cmJoin(cmMakeRange(i, args.cend()), ""_s));
|
|
}
|
|
#endif
|
|
return true;
|
|
} else if (*i == "STATUS") {
|
|
level = Message::LogLevel::LOG_STATUS;
|
|
++i;
|
|
} else if (*i == "VERBOSE") {
|
|
level = Message::LogLevel::LOG_VERBOSE;
|
|
++i;
|
|
} else if (*i == "DEBUG") {
|
|
level = Message::LogLevel::LOG_DEBUG;
|
|
++i;
|
|
} else if (*i == "TRACE") {
|
|
level = Message::LogLevel::LOG_TRACE;
|
|
++i;
|
|
} else if (*i == "DEPRECATION") {
|
|
if (mf.IsOn("CMAKE_ERROR_DEPRECATED")) {
|
|
fatal = true;
|
|
type = MessageType::DEPRECATION_ERROR;
|
|
level = Message::LogLevel::LOG_ERROR;
|
|
} else if (!mf.IsSet("CMAKE_WARN_DEPRECATED") ||
|
|
mf.IsOn("CMAKE_WARN_DEPRECATED")) {
|
|
type = MessageType::DEPRECATION_WARNING;
|
|
level = Message::LogLevel::LOG_WARNING;
|
|
} else {
|
|
return true;
|
|
}
|
|
++i;
|
|
} else if (*i == "NOTICE") {
|
|
// `NOTICE` message type is going to be output to stderr
|
|
level = Message::LogLevel::LOG_NOTICE;
|
|
++i;
|
|
} else {
|
|
// Messages w/o any type are `NOTICE`s
|
|
level = Message::LogLevel::LOG_NOTICE;
|
|
}
|
|
assert("Message log level expected to be set" &&
|
|
level != Message::LogLevel::LOG_UNDEFINED);
|
|
|
|
Message::LogLevel desiredLevel = mf.GetCurrentLogLevel();
|
|
|
|
if (desiredLevel < level) {
|
|
// Suppress the message
|
|
return true;
|
|
}
|
|
|
|
auto message = cmJoin(cmMakeRange(i, args.cend()), "");
|
|
|
|
switch (level) {
|
|
case Message::LogLevel::LOG_ERROR:
|
|
case Message::LogLevel::LOG_WARNING:
|
|
// we've overridden the message type, above, so display it directly
|
|
mf.GetMessenger()->DisplayMessage(type, message, mf.GetBacktrace());
|
|
break;
|
|
|
|
case Message::LogLevel::LOG_NOTICE:
|
|
cmSystemTools::Message(IndentText(message, mf));
|
|
#ifdef CMake_ENABLE_DEBUGGER
|
|
if (mf.GetCMakeInstance()->GetDebugAdapter()) {
|
|
mf.GetCMakeInstance()->GetDebugAdapter()->OnMessageOutput(type,
|
|
message);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case Message::LogLevel::LOG_STATUS:
|
|
switch (checkingType) {
|
|
case Message::CheckType::CHECK_START:
|
|
mf.DisplayStatus(IndentText(message, mf), -1);
|
|
mf.GetCMakeInstance()->PushCheckInProgressMessage(message);
|
|
break;
|
|
|
|
case Message::CheckType::CHECK_PASS:
|
|
ReportCheckResult("CHECK_PASS"_s, message, mf);
|
|
break;
|
|
|
|
case Message::CheckType::CHECK_FAIL:
|
|
ReportCheckResult("CHECK_FAIL"_s, message, mf);
|
|
break;
|
|
|
|
default:
|
|
mf.DisplayStatus(IndentText(message, mf), -1);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Message::LogLevel::LOG_VERBOSE:
|
|
case Message::LogLevel::LOG_DEBUG:
|
|
case Message::LogLevel::LOG_TRACE:
|
|
mf.DisplayStatus(IndentText(message, mf), -1);
|
|
break;
|
|
|
|
default:
|
|
assert("Unexpected log level! Review the `cmMessageCommand.cxx`." &&
|
|
false);
|
|
break;
|
|
}
|
|
|
|
if (fatal) {
|
|
cmSystemTools::SetFatalErrorOccurred();
|
|
}
|
|
return true;
|
|
}
|