message: Add CONFIGURE_LOG mode to record a message in the configure log

Provide a replacement for `file(APPEND .../CMake{Output,Error}.log)`
that records messages in the configure log.

Issue: #23200
This commit is contained in:
Brad King 2023-01-16 14:32:36 -05:00
parent 645671d36f
commit a78cba5197
13 changed files with 164 additions and 1 deletions

View File

@ -14,6 +14,8 @@ Synopsis
`Reporting checks`_
message(<checkState> "message text" ...)
`Configure Log`_
message(CONFIGURE_LOG <text>...)
General messages
^^^^^^^^^^^^^^^^
@ -194,6 +196,54 @@ Output from the above would appear something like the following::
-- Finding partB - not found
-- Finding my things - missing components: B
Configure Log
^^^^^^^^^^^^^
.. versionadded:: 3.26
.. code-block:: cmake
message(CONFIGURE_LOG <text>...)
Record a :ref:`configure-log message event <message configure-log event>`
with the specified ``<text>``. By convention, if the text contains more
than one line, the first line should be a summary of the event.
This mode is intended to record the details of a system inspection check
or other one-time operation guarded by a cache entry, but that is not
performed using :command:`try_compile` or :command:`try_run`, which
automatically log their details. Projects should avoid calling it every
time CMake runs. For example:
.. code-block:: cmake
if (NOT DEFINED MY_CHECK_RESULT)
# Print check summary in configure output.
message(CHECK_START "My Check")
# ... perform system inspection, e.g., with execute_process ...
# Cache the result so we do not run the check again.
set(MY_CHECK_RESULT "${MY_CHECK_RESULT}" CACHE INTERNAL "My Check")
# Record the check details in the cmake-configure-log.
message(CONFIGURE_LOG
"My Check Result: ${MY_CHECK_RESULT}\n"
"${details}"
)
# Print check result in configure output.
if(MY_CHECK_RESULT)
message(CHECK_PASS "passed")
else()
message(CHECK_FAIL "failed")
endif()
endif()
If no project is currently being configured, such as in
:ref:`cmake -P <Script Processing Mode>` script mode,
this command does nothing.
See Also
^^^^^^^^

View File

@ -131,6 +131,38 @@ The keys common to all events are:
Additional mapping keys are specific to each (versioned) event kind,
described below.
.. _`message configure-log event`:
Event Kind ``message``
----------------------
The :command:`message(CONFIGURE_LOG)` command logs ``message`` events.
There is only one ``message`` event major version, version 1.
.. _`message-v1 event`:
``message-v1`` Event
^^^^^^^^^^^^^^^^^^^^
A ``message-v1`` event is a YAML mapping:
.. code-block:: yaml
kind: "message-v1"
backtrace:
- "CMakeLists.txt:123 (message)"
checks:
- "Checking for something"
message: |
# ...
The keys specific to ``message-v1`` mappings are:
``message``
A YAML literal block scalar containing the message text,
represented using our `Text Block Encoding`_.
.. _`try_compile configure-log event`:
Event Kind ``try_compile``

View File

@ -7,6 +7,9 @@ Configure Log
* The :manual:`cmake-file-api(7)` gained a new "configureLog" object kind
that enables stable access to the :manual:`cmake-configure-log(7)`.
* The :command:`message` command gained a ``CONFIGURE_LOG`` mode to
record an entry in the :manual:`cmake-configure-log(7)`.
* The :command:`try_compile` and :command:`try_run` commands gained
a ``LOG_DESCRIPTION`` option specifying text to be recorded in the
:manual:`cmake-configure-log(7)`.

View File

@ -52,6 +52,7 @@ Json::Value ConfigureLog::DumpEventKindNames()
// major version of the configureLog object kind is needed.
Json::Value eventKindNames = Json::arrayValue;
if (this->Version == 1) {
eventKindNames.append("message-v1"); // WriteMessageEvent
eventKindNames.append("try_compile-v1"); // WriteTryCompileEvent
eventKindNames.append("try_run-v1"); // WriteTryRunEvent
}

View File

@ -8,6 +8,7 @@
#include <cm/string_view>
#include <cmext/string_view>
#include "cmConfigureLog.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@ -64,6 +65,25 @@ void ReportCheckResult(cm::string_view what, std::string result,
}
}
namespace {
#ifndef CMAKE_BOOTSTRAP
void WriteMessageEvent(cmConfigureLog& log, cmMakefile const& mf,
std::string const& message)
{
// Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
static const std::vector<unsigned long> LogVersionsWithMessageV1{ 1 };
if (log.IsAnyLogVersionEnabled(LogVersionsWithMessageV1)) {
log.BeginEvent("message-v1");
log.WriteBacktrace(mf);
log.WriteChecks(mf);
log.WriteLiteralTextBlock("message"_s, message);
log.EndEvent();
}
}
#endif
}
} // anonymous namespace
// cmLibraryCommand
@ -121,6 +141,14 @@ bool cmMessageCommand(std::vector<std::string> const& args,
level = Message::LogLevel::LOG_STATUS;
checkingType = CheckingType::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;

View File

@ -14,7 +14,7 @@ def check_object_configureLog(o):
assert os.path.exists(path)
eventKindNames = o["eventKindNames"]
assert is_list(eventKindNames)
assert sorted(eventKindNames) == ["try_compile-v1", "try_run-v1"]
assert sorted(eventKindNames) == ["message-v1", "try_compile-v1", "try_run-v1"]
assert is_dict(index)
assert sorted(index.keys()) == ["cmake", "objects", "reply"]

View File

@ -0,0 +1,30 @@
^
---
events:
-
kind: "message-v1"
backtrace:
- "ConfigureLog.cmake:[0-9]+ \(message\)"
- "CMakeLists.txt:[0-9]+ \(include\)"
message: |
Message 0
-
kind: "message-v1"
backtrace:
- "ConfigureLog.cmake:[0-9]+ \(message\)"
- "CMakeLists.txt:[0-9]+ \(include\)"
checks:
- "Check 1"
message: |
Message 1
-
kind: "message-v1"
backtrace:
- "ConfigureLog.cmake:[0-9]+ \(message\)"
- "CMakeLists.txt:[0-9]+ \(include\)"
checks:
- "Check 2"
- "Check 1"
message: |
Message 2
\.\.\.$

View File

@ -0,0 +1,4 @@
-- Check 1
-- Check 2
-- Check 2 - passed
-- Check 1 - passed

View File

@ -0,0 +1,7 @@
message(CONFIGURE_LOG "Message 0")
message(CHECK_START "Check 1")
message(CONFIGURE_LOG "Message 1")
message(CHECK_START "Check 2")
message(CONFIGURE_LOG "Message 2")
message(CHECK_PASS "passed")
message(CHECK_PASS "passed")

View File

@ -0,0 +1 @@
^$

View File

@ -0,0 +1,4 @@
-- Check 1
-- Check 2
-- Check 2 - passed
-- Check 1 - passed

View File

@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/ConfigureLog.cmake")

View File

@ -1,7 +1,9 @@
include(RunCMake)
run_cmake_script(ConfigureLogScript)
run_cmake_script(newline)
run_cmake(ConfigureLog)
run_cmake(defaultmessage)
run_cmake(nomessage)
run_cmake(message-internal-warning)