cmMessageCommand.cxx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include "cmMessageCommand.h"
  4. #include <cassert>
  5. #include <memory>
  6. #include <utility>
  7. #include <cm/string_view>
  8. #include <cmext/string_view>
  9. #include "cmConfigureLog.h"
  10. #include "cmExecutionStatus.h"
  11. #include "cmList.h"
  12. #include "cmMakefile.h"
  13. #include "cmMessageType.h"
  14. #include "cmMessenger.h"
  15. #include "cmRange.h"
  16. #include "cmStringAlgorithms.h"
  17. #include "cmSystemTools.h"
  18. #include "cmake.h"
  19. #ifdef CMake_ENABLE_DEBUGGER
  20. # include "cmDebuggerAdapter.h"
  21. #endif
  22. namespace {
  23. std::string IndentText(std::string text, cmMakefile& mf)
  24. {
  25. auto indent =
  26. cmList{ mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT") }.join("");
  27. auto const showContext = mf.GetCMakeInstance()->GetShowLogContext() ||
  28. mf.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW");
  29. if (showContext) {
  30. auto context =
  31. cmList{ mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT") }.join(".");
  32. if (!context.empty()) {
  33. indent.insert(0u, cmStrCat("["_s, context, "] "_s));
  34. }
  35. }
  36. if (!indent.empty()) {
  37. cmSystemTools::ReplaceString(text, "\n", "\n" + indent);
  38. text.insert(0u, indent);
  39. }
  40. return text;
  41. }
  42. void ReportCheckResult(cm::string_view what, std::string result,
  43. cmMakefile& mf)
  44. {
  45. if (mf.GetCMakeInstance()->HasCheckInProgress()) {
  46. auto text = mf.GetCMakeInstance()->GetTopCheckInProgressMessage() + " - " +
  47. std::move(result);
  48. mf.DisplayStatus(IndentText(std::move(text), mf), -1);
  49. } else {
  50. mf.GetMessenger()->DisplayMessage(
  51. MessageType::AUTHOR_WARNING,
  52. cmStrCat("Ignored "_s, what, " without CHECK_START"_s),
  53. mf.GetBacktrace());
  54. }
  55. }
  56. namespace {
  57. #ifndef CMAKE_BOOTSTRAP
  58. void WriteMessageEvent(cmConfigureLog& log, cmMakefile const& mf,
  59. std::string const& message)
  60. {
  61. // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
  62. static std::vector<unsigned int> const LogVersionsWithMessageV1{ 1 };
  63. if (log.IsAnyLogVersionEnabled(LogVersionsWithMessageV1)) {
  64. log.BeginEvent("message-v1", mf);
  65. log.WriteLiteralTextBlock("message"_s, message);
  66. log.EndEvent();
  67. }
  68. }
  69. #endif
  70. }
  71. } // anonymous namespace
  72. // cmLibraryCommand
  73. bool cmMessageCommand(std::vector<std::string> const& args,
  74. cmExecutionStatus& status)
  75. {
  76. if (args.empty()) {
  77. status.SetError("called with incorrect number of arguments");
  78. return false;
  79. }
  80. auto& mf = status.GetMakefile();
  81. auto i = args.cbegin();
  82. auto type = MessageType::MESSAGE;
  83. auto fatal = false;
  84. auto level = Message::LogLevel::LOG_UNDEFINED;
  85. auto checkingType = Message::CheckType::UNDEFINED;
  86. if (*i == "SEND_ERROR") {
  87. type = MessageType::FATAL_ERROR;
  88. level = Message::LogLevel::LOG_ERROR;
  89. ++i;
  90. } else if (*i == "FATAL_ERROR") {
  91. fatal = true;
  92. type = MessageType::FATAL_ERROR;
  93. level = Message::LogLevel::LOG_ERROR;
  94. ++i;
  95. } else if (*i == "WARNING") {
  96. type = MessageType::WARNING;
  97. level = Message::LogLevel::LOG_WARNING;
  98. ++i;
  99. } else if (*i == "AUTHOR_WARNING") {
  100. if (mf.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
  101. !mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
  102. fatal = true;
  103. type = MessageType::AUTHOR_ERROR;
  104. level = Message::LogLevel::LOG_ERROR;
  105. } else if (!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
  106. type = MessageType::AUTHOR_WARNING;
  107. level = Message::LogLevel::LOG_WARNING;
  108. } else {
  109. return true;
  110. }
  111. ++i;
  112. } else if (*i == "CHECK_START") {
  113. level = Message::LogLevel::LOG_STATUS;
  114. checkingType = Message::CheckType::CHECK_START;
  115. ++i;
  116. } else if (*i == "CHECK_PASS") {
  117. level = Message::LogLevel::LOG_STATUS;
  118. checkingType = Message::CheckType::CHECK_PASS;
  119. ++i;
  120. } else if (*i == "CHECK_FAIL") {
  121. level = Message::LogLevel::LOG_STATUS;
  122. checkingType = Message::CheckType::CHECK_FAIL;
  123. ++i;
  124. } else if (*i == "CONFIGURE_LOG") {
  125. #ifndef CMAKE_BOOTSTRAP
  126. if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) {
  127. ++i;
  128. WriteMessageEvent(*log, mf, cmJoin(cmMakeRange(i, args.cend()), ""_s));
  129. }
  130. #endif
  131. return true;
  132. } else if (*i == "STATUS") {
  133. level = Message::LogLevel::LOG_STATUS;
  134. ++i;
  135. } else if (*i == "VERBOSE") {
  136. level = Message::LogLevel::LOG_VERBOSE;
  137. ++i;
  138. } else if (*i == "DEBUG") {
  139. level = Message::LogLevel::LOG_DEBUG;
  140. ++i;
  141. } else if (*i == "TRACE") {
  142. level = Message::LogLevel::LOG_TRACE;
  143. ++i;
  144. } else if (*i == "DEPRECATION") {
  145. if (mf.IsOn("CMAKE_ERROR_DEPRECATED")) {
  146. fatal = true;
  147. type = MessageType::DEPRECATION_ERROR;
  148. level = Message::LogLevel::LOG_ERROR;
  149. } else if (!mf.IsSet("CMAKE_WARN_DEPRECATED") ||
  150. mf.IsOn("CMAKE_WARN_DEPRECATED")) {
  151. type = MessageType::DEPRECATION_WARNING;
  152. level = Message::LogLevel::LOG_WARNING;
  153. } else {
  154. return true;
  155. }
  156. ++i;
  157. } else if (*i == "NOTICE") {
  158. // `NOTICE` message type is going to be output to stderr
  159. level = Message::LogLevel::LOG_NOTICE;
  160. ++i;
  161. } else {
  162. // Messages w/o any type are `NOTICE`s
  163. level = Message::LogLevel::LOG_NOTICE;
  164. }
  165. assert("Message log level expected to be set" &&
  166. level != Message::LogLevel::LOG_UNDEFINED);
  167. Message::LogLevel desiredLevel = mf.GetCurrentLogLevel();
  168. if (desiredLevel < level) {
  169. // Suppress the message
  170. return true;
  171. }
  172. auto message = cmJoin(cmMakeRange(i, args.cend()), "");
  173. switch (level) {
  174. case Message::LogLevel::LOG_ERROR:
  175. case Message::LogLevel::LOG_WARNING:
  176. // we've overridden the message type, above, so display it directly
  177. mf.GetMessenger()->DisplayMessage(type, message, mf.GetBacktrace());
  178. break;
  179. case Message::LogLevel::LOG_NOTICE:
  180. cmSystemTools::Message(IndentText(message, mf));
  181. #ifdef CMake_ENABLE_DEBUGGER
  182. if (mf.GetCMakeInstance()->GetDebugAdapter()) {
  183. mf.GetCMakeInstance()->GetDebugAdapter()->OnMessageOutput(type,
  184. message);
  185. }
  186. #endif
  187. break;
  188. case Message::LogLevel::LOG_STATUS:
  189. switch (checkingType) {
  190. case Message::CheckType::CHECK_START:
  191. mf.DisplayStatus(IndentText(message, mf), -1);
  192. mf.GetCMakeInstance()->PushCheckInProgressMessage(message);
  193. break;
  194. case Message::CheckType::CHECK_PASS:
  195. ReportCheckResult("CHECK_PASS"_s, message, mf);
  196. break;
  197. case Message::CheckType::CHECK_FAIL:
  198. ReportCheckResult("CHECK_FAIL"_s, message, mf);
  199. break;
  200. default:
  201. mf.DisplayStatus(IndentText(message, mf), -1);
  202. break;
  203. }
  204. break;
  205. case Message::LogLevel::LOG_VERBOSE:
  206. case Message::LogLevel::LOG_DEBUG:
  207. case Message::LogLevel::LOG_TRACE:
  208. mf.DisplayStatus(IndentText(message, mf), -1);
  209. break;
  210. default:
  211. assert("Unexpected log level! Review the `cmMessageCommand.cxx`." &&
  212. false);
  213. break;
  214. }
  215. if (fatal) {
  216. cmSystemTools::SetFatalErrorOccurred();
  217. }
  218. return true;
  219. }