1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmMessageCommand.h"
9 #include <cm/string_view>
10 #include <cmext/string_view>
12 #include "cmConfigureLog.h"
13 #include "cmExecutionStatus.h"
15 #include "cmMakefile.h"
16 #include "cmMessageType.h"
17 #include "cmMessenger.h"
19 #include "cmStringAlgorithms.h"
20 #include "cmSystemTools.h"
23 #ifdef CMake_ENABLE_DEBUGGER
24 # include "cmDebuggerAdapter.h"
29 enum class CheckingType
37 std::string
IndentText(std::string text
, cmMakefile
& mf
)
40 cmList
{ mf
.GetSafeDefinition("CMAKE_MESSAGE_INDENT") }.join("");
42 const auto showContext
= mf
.GetCMakeInstance()->GetShowLogContext() ||
43 mf
.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW");
46 cmList
{ mf
.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT") }.join(".");
47 if (!context
.empty()) {
48 indent
.insert(0u, cmStrCat("["_s
, context
, "] "_s
));
52 if (!indent
.empty()) {
53 cmSystemTools::ReplaceString(text
, "\n", "\n" + indent
);
54 text
.insert(0u, indent
);
59 void ReportCheckResult(cm::string_view what
, std::string result
,
62 if (mf
.GetCMakeInstance()->HasCheckInProgress()) {
63 auto text
= mf
.GetCMakeInstance()->GetTopCheckInProgressMessage() + " - " +
65 mf
.DisplayStatus(IndentText(std::move(text
), mf
), -1);
67 mf
.GetMessenger()->DisplayMessage(
68 MessageType::AUTHOR_WARNING
,
69 cmStrCat("Ignored "_s
, what
, " without CHECK_START"_s
),
75 #ifndef CMAKE_BOOTSTRAP
76 void WriteMessageEvent(cmConfigureLog
& log
, cmMakefile
const& mf
,
77 std::string
const& message
)
79 // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
80 static const std::vector
<unsigned long> LogVersionsWithMessageV1
{ 1 };
82 if (log
.IsAnyLogVersionEnabled(LogVersionsWithMessageV1
)) {
83 log
.BeginEvent("message-v1", mf
);
84 log
.WriteLiteralTextBlock("message"_s
, message
);
91 } // anonymous namespace
94 bool cmMessageCommand(std::vector
<std::string
> const& args
,
95 cmExecutionStatus
& status
)
98 status
.SetError("called with incorrect number of arguments");
102 auto& mf
= status
.GetMakefile();
104 auto i
= args
.cbegin();
106 auto type
= MessageType::MESSAGE
;
108 auto level
= Message::LogLevel::LOG_UNDEFINED
;
109 auto checkingType
= CheckingType::UNDEFINED
;
110 if (*i
== "SEND_ERROR") {
111 type
= MessageType::FATAL_ERROR
;
112 level
= Message::LogLevel::LOG_ERROR
;
114 } else if (*i
== "FATAL_ERROR") {
116 type
= MessageType::FATAL_ERROR
;
117 level
= Message::LogLevel::LOG_ERROR
;
119 } else if (*i
== "WARNING") {
120 type
= MessageType::WARNING
;
121 level
= Message::LogLevel::LOG_WARNING
;
123 } else if (*i
== "AUTHOR_WARNING") {
124 if (mf
.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
125 !mf
.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
127 type
= MessageType::AUTHOR_ERROR
;
128 level
= Message::LogLevel::LOG_ERROR
;
129 } else if (!mf
.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
130 type
= MessageType::AUTHOR_WARNING
;
131 level
= Message::LogLevel::LOG_WARNING
;
136 } else if (*i
== "CHECK_START") {
137 level
= Message::LogLevel::LOG_STATUS
;
138 checkingType
= CheckingType::CHECK_START
;
140 } else if (*i
== "CHECK_PASS") {
141 level
= Message::LogLevel::LOG_STATUS
;
142 checkingType
= CheckingType::CHECK_PASS
;
144 } else if (*i
== "CHECK_FAIL") {
145 level
= Message::LogLevel::LOG_STATUS
;
146 checkingType
= CheckingType::CHECK_FAIL
;
148 } else if (*i
== "CONFIGURE_LOG") {
149 #ifndef CMAKE_BOOTSTRAP
150 if (cmConfigureLog
* log
= mf
.GetCMakeInstance()->GetConfigureLog()) {
152 WriteMessageEvent(*log
, mf
, cmJoin(cmMakeRange(i
, args
.cend()), ""_s
));
156 } else if (*i
== "STATUS") {
157 level
= Message::LogLevel::LOG_STATUS
;
159 } else if (*i
== "VERBOSE") {
160 level
= Message::LogLevel::LOG_VERBOSE
;
162 } else if (*i
== "DEBUG") {
163 level
= Message::LogLevel::LOG_DEBUG
;
165 } else if (*i
== "TRACE") {
166 level
= Message::LogLevel::LOG_TRACE
;
168 } else if (*i
== "DEPRECATION") {
169 if (mf
.IsOn("CMAKE_ERROR_DEPRECATED")) {
171 type
= MessageType::DEPRECATION_ERROR
;
172 level
= Message::LogLevel::LOG_ERROR
;
173 } else if (!mf
.IsSet("CMAKE_WARN_DEPRECATED") ||
174 mf
.IsOn("CMAKE_WARN_DEPRECATED")) {
175 type
= MessageType::DEPRECATION_WARNING
;
176 level
= Message::LogLevel::LOG_WARNING
;
181 } else if (*i
== "NOTICE") {
182 // `NOTICE` message type is going to be output to stderr
183 level
= Message::LogLevel::LOG_NOTICE
;
186 // Messages w/o any type are `NOTICE`s
187 level
= Message::LogLevel::LOG_NOTICE
;
189 assert("Message log level expected to be set" &&
190 level
!= Message::LogLevel::LOG_UNDEFINED
);
192 Message::LogLevel desiredLevel
= mf
.GetCurrentLogLevel();
194 if (desiredLevel
< level
) {
195 // Suppress the message
199 auto message
= cmJoin(cmMakeRange(i
, args
.cend()), "");
202 case Message::LogLevel::LOG_ERROR
:
203 case Message::LogLevel::LOG_WARNING
:
204 // we've overridden the message type, above, so display it directly
205 mf
.GetMessenger()->DisplayMessage(type
, message
, mf
.GetBacktrace());
208 case Message::LogLevel::LOG_NOTICE
:
209 cmSystemTools::Message(IndentText(message
, mf
));
210 #ifdef CMake_ENABLE_DEBUGGER
211 if (mf
.GetCMakeInstance()->GetDebugAdapter() != nullptr) {
212 mf
.GetCMakeInstance()->GetDebugAdapter()->OnMessageOutput(type
,
218 case Message::LogLevel::LOG_STATUS
:
219 switch (checkingType
) {
220 case CheckingType::CHECK_START
:
221 mf
.DisplayStatus(IndentText(message
, mf
), -1);
222 mf
.GetCMakeInstance()->PushCheckInProgressMessage(message
);
225 case CheckingType::CHECK_PASS
:
226 ReportCheckResult("CHECK_PASS"_s
, message
, mf
);
229 case CheckingType::CHECK_FAIL
:
230 ReportCheckResult("CHECK_FAIL"_s
, message
, mf
);
234 mf
.DisplayStatus(IndentText(message
, mf
), -1);
239 case Message::LogLevel::LOG_VERBOSE
:
240 case Message::LogLevel::LOG_DEBUG
:
241 case Message::LogLevel::LOG_TRACE
:
242 mf
.DisplayStatus(IndentText(message
, mf
), -1);
246 assert("Unexpected log level! Review the `cmMessageCommand.cxx`." &&
252 cmSystemTools::SetFatalErrorOccurred();