summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/index.rst1
-rw-r--r--Help/manual/cmake-configure-log.7.rst254
-rw-r--r--Help/release/dev/configure-log.rst5
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/cmConfigureLog.cxx261
-rw-r--r--Source/cmConfigureLog.h68
-rw-r--r--Source/cmCoreTryCompile.cxx78
-rw-r--r--Source/cmCoreTryCompile.h20
-rw-r--r--Source/cmTryCompileCommand.cxx30
-rw-r--r--Source/cmTryRunCommand.cxx108
-rw-r--r--Source/cmake.cxx13
-rw-r--r--Source/cmake.h8
-rw-r--r--Tests/RunCMake/RunCMake.cmake66
-rw-r--r--Tests/RunCMake/try_compile/Inspect-config.txt34
-rw-r--r--Tests/RunCMake/try_compile/SourceFromBadName-config.txt1
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog-bad.c1
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog-config.txt96
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog-test.c9
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog.cmake18
-rw-r--r--Tests/RunCMake/try_run/RunCMakeTest.cmake1
20 files changed, 995 insertions, 79 deletions
diff --git a/Help/index.rst b/Help/index.rst
index fdbf847..16c8f25 100644
--- a/Help/index.rst
+++ b/Help/index.rst
@@ -57,6 +57,7 @@ Reference Manuals
/manual/cmake-buildsystem.7
/manual/cmake-commands.7
/manual/cmake-compile-features.7
+ /manual/cmake-configure-log.7
/manual/cmake-developer.7
/manual/cmake-env-variables.7
/manual/cmake-file-api.7
diff --git a/Help/manual/cmake-configure-log.7.rst b/Help/manual/cmake-configure-log.7.rst
new file mode 100644
index 0000000..7f395f5
--- /dev/null
+++ b/Help/manual/cmake-configure-log.7.rst
@@ -0,0 +1,254 @@
+.. cmake-manual-description: CMake Configure Log
+
+cmake-configure-log(7)
+**********************
+
+.. versionadded:: 3.26
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+CMake writes a running log, known as the configure log,
+of certain events that occur during the "configure" step.
+The log file is located at::
+
+ ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeConfigureLog.yaml
+
+The configure log does *not* contain a log of all output, errors,
+or messages printed while configuring a project. It is a log of
+detailed information about specific events, such as toolchain inspection
+by :command:`try_compile`, meant for use in debugging the configuration
+of a build tree.
+
+Log Structure
+=============
+
+The configure log is designed to be both machine- and human-readable.
+
+The log file is a YAML document stream containing zero or more YAML
+documents separated by document markers. Each document begins
+with a ``---`` document marker line, contains a single YAML mapping
+that logs events from one CMake "configure" step, and, if the configure
+step finished normally, ends with a ``...`` document marker line:
+
+.. code-block:: yaml
+
+ ---
+ events:
+ -
+ kind: "try_compile-v1"
+ # (other fields omitted)
+ -
+ kind: "try_compile-v1"
+ # (other fields omitted)
+ ...
+
+A new document is appended to the log every time CMake configures
+the build tree and logs new events.
+
+The keys of the each document root mapping are:
+
+``events``
+ A YAML block sequence of nodes corresponding to events logged during
+ one CMake "configure" step. Each event is a YAML node containing one
+ of the `Event Kinds`_ documented below.
+
+Log Versioning
+--------------
+
+Each of the `Event Kinds`_ is versioned independently. The set of
+keys an event's log entry provides is specific to its major version.
+When an event is logged, the latest version of its event kind that is
+known to the running version of CMake is always written to the log.
+
+Tools reading the configure log must ignore event kinds and versions
+they do not understand:
+
+* A future version of CMake may introduce a new event kind or version.
+
+* If an existing build tree is re-configured with a different version of
+ CMake, the log may contain different versions of the same event kind.
+
+Text Block Encoding
+-------------------
+
+In order to make the log human-readable, text blocks are always
+represented using YAML literal block scalars (``|``).
+Since literal block scalars do not support escaping, backslashes
+and non-printable characters are encoded at the application layer:
+
+* ``\\`` encodes a backslash.
+* ``\xXX`` encodes a byte using two hexadecimal digits, ``XX``.
+
+.. _`configure-log event kinds`:
+
+Event Kinds
+===========
+
+Every event kind is represented by a YAML mapping of the form:
+
+.. code-block:: yaml
+
+ kind: "<kind>-v<major>"
+ backtrace:
+ - "<file>:<line> (<function>)"
+ #...event-specific keys...
+
+The keys common to all events are:
+
+``kind``
+ A string identifying the event kind and major version.
+
+``backtrace``
+ A YAML block sequence reporting the call stack of CMake source
+ locations at which the event occurred. Each node is a string
+ specifying one location formatted as ``<file>:<line> (<function>)``.
+
+Additional mapping keys are specific to each (versioned) event kind,
+described below.
+
+Event Kind ``try_compile``
+--------------------------
+
+The :command:`try_compile` command logs ``try_compile`` events.
+
+There is only one ``try_compile`` event major version, version 1.
+
+.. _`try_compile-v1 event`:
+
+``try_compile-v1`` Event
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+A ``try_compile-v1`` event is a YAML mapping:
+
+.. code-block:: yaml
+
+ kind: "try_compile-v1"
+ backtrace:
+ - "CMakeLists.txt:123 (try_compile)"
+ directories:
+ source: "/path/to/.../TryCompile-01234"
+ binary: "/path/to/.../TryCompile-01234"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: |
+ # ...
+ exitCode: 0
+
+The keys specific to ``try_compile-v1`` mappings are:
+
+``directories``
+ A mapping describing the directories associated with the
+ compilation attempt. It has the following keys:
+
+ ``source``
+ String specifying the source directory of the
+ :command:`try_compile` project.
+
+ ``binary``
+ String specifying the binary directory of the
+ :command:`try_compile` project.
+ For non-project invocations, this is often the same as
+ the source directory.
+
+``buildResult``
+ A mapping describing the result of compiling the test code.
+ It has the following keys:
+
+ ``variable``
+ A string specifying the name of the CMake variable
+ storing the result of trying to build the test project.
+
+ ``cached``
+ A boolean indicating whether the above result ``variable``
+ is stored in the CMake cache.
+
+ ``stdout``
+ A YAML literal block scalar containing the output from building
+ the test project, represented using our `Text Block Encoding`_.
+ This contains build output from both stdout and stderr.
+
+ ``exitCode``
+ An integer specifying the build tool exit code from trying
+ to build the test project.
+
+Event Kind ``try_run``
+----------------------
+
+The :command:`try_run` command logs ``try_run`` events.
+
+There is only one ``try_run`` event major version, version 1.
+
+.. _`try_run-v1 event`:
+
+``try_run-v1`` Event
+^^^^^^^^^^^^^^^^^^^^
+
+A ``try_run-v1`` event is a YAML mapping:
+
+.. code-block:: yaml
+
+ kind: "try_run-v1"
+ backtrace:
+ - "CMakeLists.txt:456 (try_run)"
+ directories:
+ source: "/path/to/.../TryCompile-56789"
+ binary: "/path/to/.../TryCompile-56789"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: |
+ # ...
+ exitCode: 0
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ stdout: |
+ # ...
+ stderr: |
+ # ...
+ exitCode: 0
+
+The keys specific to ``try_run-v1`` mappings include those
+documented by the `try_compile-v1 event`_, plus:
+
+``runResult``
+ A mapping describing the result of running the test code.
+ It has the following keys:
+
+ ``variable``
+ A string specifying the name of the CMake variable
+ storing the result of trying to run the test executable.
+
+ ``cached``
+ A boolean indicating whether the above result ``variable``
+ is stored in the CMake cache.
+
+ ``stdout``
+ An optional key that is present when the test project built successfully.
+ Its value is a YAML literal block scalar containing output from running
+ the test executable, represented using our `Text Block Encoding`_.
+
+ If ``RUN_OUTPUT_VARIABLE`` was used, stdout and stderr are captured
+ together, so this will contain both. Otherwise, this will contain
+ only the stdout output.
+
+ ``stderr``
+ An optional key that is present when the test project built successfully
+ and the ``RUN_OUTPUT_VARIABLE`` option was not used.
+ Its value is a YAML literal block scalar containing output from running
+ the test executable, represented using our `Text Block Encoding`_.
+
+ If ``RUN_OUTPUT_VARIABLE`` was used, stdout and stderr are captured
+ together in the ``stdout`` key, and this key will not be present.
+ Otherwise, this will contain the stderr output.
+
+ ``exitCode``
+ An optional key that is present when the test project built successfully.
+ Its value is an integer specifying the exit code, or a string containing
+ an error message, from trying to run the test executable.
diff --git a/Help/release/dev/configure-log.rst b/Help/release/dev/configure-log.rst
new file mode 100644
index 0000000..8518b21
--- /dev/null
+++ b/Help/release/dev/configure-log.rst
@@ -0,0 +1,5 @@
+Configure Log
+-------------
+
+* CMake now writes a YAML log of configure-time checks.
+ See the :manual:`cmake-configure-log(7)` manual.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 41a901a..db928fc 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -160,6 +160,8 @@ add_library(
cmComputeLinkInformation.h
cmComputeTargetDepends.h
cmComputeTargetDepends.cxx
+ cmConfigureLog.h
+ cmConfigureLog.cxx
cmConsoleBuf.h
cmConsoleBuf.cxx
cmConstStack.h
diff --git a/Source/cmConfigureLog.cxx b/Source/cmConfigureLog.cxx
new file mode 100644
index 0000000..c2a5b5e
--- /dev/null
+++ b/Source/cmConfigureLog.cxx
@@ -0,0 +1,261 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmConfigureLog.h"
+
+#include <cassert>
+#include <cstdio>
+#include <iterator>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include <cm3p/json/writer.h>
+
+#include "cm_utf8.h"
+
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmConfigureLog::cmConfigureLog(std::string logDir,
+ std::vector<unsigned long> logVersions)
+ : LogDir(std::move(logDir))
+ , LogVersions(std::move(logVersions))
+{
+ // Always emit events for the latest log version.
+ static const unsigned long LatestLogVersion = 1;
+ if (!cm::contains(this->LogVersions, LatestLogVersion)) {
+ this->LogVersions.emplace_back(LatestLogVersion);
+ }
+
+ Json::StreamWriterBuilder builder;
+ this->Encoder.reset(builder.newStreamWriter());
+}
+
+cmConfigureLog::~cmConfigureLog()
+{
+ if (this->Opened) {
+ this->EndObject();
+ this->Stream << "...\n";
+ }
+}
+
+bool cmConfigureLog::IsAnyLogVersionEnabled(
+ std::vector<unsigned long> const& v) const
+{
+ // Both input lists are sorted. Look for a matching element.
+ auto i1 = v.cbegin();
+ auto i2 = this->LogVersions.cbegin();
+ while (i1 != v.cend() && i2 != this->LogVersions.cend()) {
+ if (*i1 < *i2) {
+ ++i1;
+ } else if (*i2 < *i1) {
+ ++i2;
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmConfigureLog::WriteBacktrace(cmMakefile const& mf)
+{
+ std::vector<std::string> backtrace;
+ auto root = mf.GetCMakeInstance()->GetHomeDirectory();
+ for (auto bt = mf.GetBacktrace(); !bt.Empty(); bt = bt.Pop()) {
+ auto t = bt.Top();
+ if (!t.Name.empty() || t.Line == cmListFileContext::DeferPlaceholderLine) {
+ t.FilePath = cmSystemTools::RelativeIfUnder(root, t.FilePath);
+ std::ostringstream s;
+ s << t;
+ backtrace.emplace_back(s.str());
+ }
+ }
+ this->WriteValue("backtrace"_s, backtrace);
+}
+
+void cmConfigureLog::EnsureInit()
+{
+ if (this->Opened) {
+ return;
+ }
+ assert(!this->Stream.is_open());
+
+ std::string name = cmStrCat(this->LogDir, "/CMakeConfigureLog.yaml");
+ this->Stream.open(name.c_str(), std::ios::out | std::ios::app);
+
+ this->Opened = true;
+
+ this->Stream << "\n---\n";
+ this->BeginObject("events"_s);
+}
+
+cmsys::ofstream& cmConfigureLog::BeginLine()
+{
+ for (unsigned i = 0; i < this->Indent; ++i) {
+ this->Stream << " ";
+ }
+ return this->Stream;
+}
+
+void cmConfigureLog::EndLine()
+{
+ this->Stream << std::endl;
+}
+
+void cmConfigureLog::BeginObject(cm::string_view key)
+{
+ this->BeginLine() << key << ':';
+ this->EndLine();
+ ++this->Indent;
+}
+
+void cmConfigureLog::EndObject()
+{
+ assert(this->Indent);
+ --this->Indent;
+}
+
+void cmConfigureLog::BeginEvent(std::string const& kind)
+{
+ this->EnsureInit();
+
+ this->BeginLine() << '-';
+ this->EndLine();
+
+ ++this->Indent;
+
+ this->WriteValue("kind"_s, kind);
+}
+
+void cmConfigureLog::EndEvent()
+{
+ assert(this->Indent);
+ --this->Indent;
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key, std::nullptr_t)
+{
+ this->BeginLine() << key << ": null";
+ this->EndLine();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key, bool value)
+{
+ this->BeginLine() << key << ": " << (value ? "true" : "false");
+ this->EndLine();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key, int value)
+{
+ this->BeginLine() << key << ": " << value;
+ this->EndLine();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key, std::string const& value)
+{
+ this->BeginLine() << key << ": ";
+ this->Encoder->write(value, &this->Stream);
+ this->EndLine();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key,
+ std::vector<std::string> const& list)
+{
+ this->BeginObject(key);
+ for (auto const& value : list) {
+ this->BeginLine() << "- ";
+ this->Encoder->write(value, &this->Stream);
+ this->EndLine();
+ }
+ this->EndObject();
+}
+
+void cmConfigureLog::WriteLiteralTextBlock(cm::string_view key,
+ cm::string_view text)
+{
+ this->BeginLine() << key << ": |";
+ this->EndLine();
+
+ auto const l = text.length();
+ if (l) {
+ ++this->Indent;
+ this->BeginLine();
+
+ auto i = decltype(l){ 0 };
+ while (i < l) {
+ // YAML allows ' ', '\t' and "printable characters", but NOT other
+ // ASCII whitespace; those must be escaped, as must the upper UNICODE
+ // control characters (U+0080 - U+009F)
+ static constexpr unsigned int C1_LAST = 0x9F;
+ auto const c = static_cast<unsigned char>(text[i]);
+ switch (c) {
+ case '\r':
+ // Print a carriage return only if it is not followed by a line feed.
+ ++i;
+ if (i == l || text[i] != '\n') {
+ this->WriteEscape(c);
+ }
+ break;
+ case '\n':
+ // Print any line feeds except the very last one
+ if (i + 1 < l) {
+ this->EndLine();
+ this->BeginLine();
+ }
+ ++i;
+ break;
+ case '\t':
+ // Print horizontal tab verbatim
+ this->Stream.put('\t');
+ ++i;
+ break;
+ case '\\':
+ // Escape backslash for disambiguation
+ this->Stream << "\\\\";
+ ++i;
+ break;
+ default:
+ if (c >= 32 && c < 127) {
+ // Print ascii byte.
+ this->Stream.put(text[i]);
+ ++i;
+ break;
+ } else if (c > 127) {
+ // Decode a UTF-8 sequence.
+ unsigned int c32;
+ auto const* const s = text.data() + i;
+ auto const* const e = text.data() + l;
+ auto const* const n = cm_utf8_decode_character(s, e, &c32);
+ if (n > s && c32 > C1_LAST) {
+ auto const k = std::distance(s, n);
+ this->Stream.write(s, static_cast<std::streamsize>(k));
+ i += static_cast<unsigned>(k);
+ break;
+ }
+ }
+
+ // Escape non-printable byte.
+ this->WriteEscape(c);
+ ++i;
+ break;
+ }
+ }
+
+ this->EndLine();
+ --this->Indent;
+ }
+}
+
+void cmConfigureLog::WriteEscape(unsigned char c)
+{
+ char buffer[6];
+ int n = snprintf(buffer, sizeof(buffer), "\\x%02x", c);
+ if (n > 0) {
+ this->Stream.write(buffer, n);
+ }
+}
diff --git a/Source/cmConfigureLog.h b/Source/cmConfigureLog.h
new file mode 100644
index 0000000..9caac66
--- /dev/null
+++ b/Source/cmConfigureLog.h
@@ -0,0 +1,68 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmsys/FStream.hxx"
+
+namespace Json {
+class StreamWriter;
+}
+
+class cmMakefile;
+
+class cmConfigureLog
+{
+public:
+ /** Construct with the log directory and a sorted list of enabled log
+ versions. The latest log version will be enabled regardless. */
+ cmConfigureLog(std::string logDir, std::vector<unsigned long> logVersions);
+ ~cmConfigureLog();
+
+ /** Return true if at least one of the log versions in the given sorted
+ list is enabled. */
+ bool IsAnyLogVersionEnabled(std::vector<unsigned long> const& v) const;
+
+ void WriteBacktrace(cmMakefile const& mf);
+
+ void EnsureInit();
+
+ void BeginEvent(std::string const& kind);
+ void EndEvent();
+
+ void BeginObject(cm::string_view key);
+ void EndObject();
+
+ // TODO other value types
+ void WriteValue(cm::string_view key, std::nullptr_t);
+ void WriteValue(cm::string_view key, bool value);
+ void WriteValue(cm::string_view key, int value);
+ void WriteValue(cm::string_view key, std::string const& value);
+ void WriteValue(cm::string_view key, std::vector<std::string> const& list);
+
+ void WriteTextBlock(cm::string_view key, cm::string_view text);
+ void WriteLiteralTextBlock(cm::string_view key, cm::string_view text);
+
+ void WriteLiteralTextBlock(cm::string_view key, std::string const& text)
+ {
+ this->WriteLiteralTextBlock(key, cm::string_view{ text });
+ }
+
+private:
+ std::string LogDir;
+ std::vector<unsigned long> LogVersions;
+ cmsys::ofstream Stream;
+ unsigned Indent = 0;
+ bool Opened = false;
+
+ std::unique_ptr<Json::StreamWriter> Encoder;
+
+ cmsys::ofstream& BeginLine();
+ void EndLine();
+ void WriteEscape(unsigned char c);
+};
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index b44111d..25a0e2d 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -16,6 +16,7 @@
#include "cmsys/FStream.hxx"
#include "cmArgumentParser.h"
+#include "cmConfigureLog.h"
#include "cmExportTryCompileFileGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@@ -285,8 +286,8 @@ Arguments cmCoreTryCompile::ParseArgs(
return arguments;
}
-bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
- cmStateEnums::TargetType targetType)
+cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
+ Arguments& arguments, cmStateEnums::TargetType targetType)
{
this->OutputFile.clear();
// which signature were we called with ?
@@ -302,7 +303,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
arguments.SourceDirectoryOrFile->empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"No <srcdir> specified.");
- return false;
+ return cm::nullopt;
}
sourceDirectory = *arguments.SourceDirectoryOrFile;
projectName = *arguments.ProjectName;
@@ -322,7 +323,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
if (!arguments.BinaryDirectory || arguments.BinaryDirectory->empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"No <bindir> specified.");
- return false;
+ return cm::nullopt;
}
if (*arguments.BinaryDirectory == unique_binary_directory) {
// leave empty until we're ready to create it, so we don't try to remove
@@ -335,7 +336,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
MessageType::FATAL_ERROR,
cmStrCat("<bindir> is not an absolute path:\n '",
*arguments.BinaryDirectory, "'"));
- return false;
+ return cm::nullopt;
}
this->BinaryDirectory = *arguments.BinaryDirectory;
// compute the binary dir when TRY_COMPILE is called with a src file
@@ -367,7 +368,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
"IMPORTED LINK_LIBRARIES. Got ",
tgt->GetName(), " of type ",
cmState::GetTargetTypeName(tgt->GetType()), "."));
- return false;
+ return cm::nullopt;
}
if (tgt->IsImported()) {
targets.emplace_back(i);
@@ -379,28 +380,28 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
if (arguments.CopyFileTo && arguments.CopyFileTo->empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"COPY_FILE must be followed by a file path");
- return false;
+ return cm::nullopt;
}
if (arguments.CopyFileError && arguments.CopyFileError->empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE_ERROR must be followed by a variable name");
- return false;
+ return cm::nullopt;
}
if (arguments.CopyFileError && !arguments.CopyFileTo) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE_ERROR may be used only with COPY_FILE");
- return false;
+ return cm::nullopt;
}
if (arguments.Sources && arguments.Sources->empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCES must be followed by at least one source file");
- return false;
+ return cm::nullopt;
}
if (this->SrcFileSignature) {
@@ -409,19 +410,19 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCE_FROM_CONTENT requires exactly two arguments");
- return false;
+ return cm::nullopt;
}
if (arguments.SourceFromVar && arguments.SourceFromVar->size() % 2) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCE_FROM_VAR requires exactly two arguments");
- return false;
+ return cm::nullopt;
}
if (arguments.SourceFromFile && arguments.SourceFromFile->size() % 2) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCE_FROM_FILE requires exactly two arguments");
- return false;
+ return cm::nullopt;
}
} else {
// only valid for srcfile signatures
@@ -430,19 +431,19 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
MessageType::FATAL_ERROR,
cmStrCat(arguments.LangProps.begin()->first,
" allowed only in source file signature"));
- return false;
+ return cm::nullopt;
}
if (!arguments.CompileDefs.empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COMPILE_DEFINITIONS allowed only in source file signature");
- return false;
+ return cm::nullopt;
}
if (arguments.CopyFileTo) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE allowed only in source file signature");
- return false;
+ return cm::nullopt;
}
}
@@ -462,7 +463,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
e << "Attempt at a recursive or nested TRY_COMPILE in directory\n"
<< " " << this->BinaryDirectory << "\n";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return false;
+ return cm::nullopt;
}
std::string outFileName = this->BinaryDirectory + "/CMakeLists.txt";
@@ -486,7 +487,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
const auto& content = (*arguments.SourceFromContent)[i + 1];
auto out = this->WriteSource(name, content, "SOURCE_FROM_CONTENT");
if (out.empty()) {
- return false;
+ return cm::nullopt;
}
sources.emplace_back(std::move(out));
}
@@ -499,7 +500,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
const auto& content = this->Makefile->GetDefinition(var);
auto out = this->WriteSource(name, content, "SOURCE_FROM_VAR");
if (out.empty()) {
- return false;
+ return cm::nullopt;
}
sources.emplace_back(std::move(out));
}
@@ -514,7 +515,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
const auto& msg =
cmStrCat("SOURCE_FROM_FILE given invalid filename \"", dst, "\"");
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
- return false;
+ return cm::nullopt;
}
auto dstPath = cmStrCat(this->BinaryDirectory, "/", dst);
@@ -523,7 +524,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
const auto& msg = cmStrCat("SOURCE_FROM_FILE failed to copy \"", src,
"\": ", result.GetString());
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
- return false;
+ return cm::nullopt;
}
sources.emplace_back(std::move(dstPath));
@@ -550,7 +551,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
err << cmJoin(langs, " ");
err << "\nSee project() command to enable other languages.";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err.str());
- return false;
+ return cm::nullopt;
}
}
@@ -577,7 +578,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
<< cmSystemTools::GetLastSystemError();
/* clang-format on */
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return false;
+ return cm::nullopt;
}
cmValue def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
@@ -778,7 +779,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"could not write export file.");
fclose(fout);
- return false;
+ return cm::nullopt;
}
fprintf(fout, "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n",
fname.c_str());
@@ -1111,7 +1112,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
}
if (!arguments.CopyFileError) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
- return false;
+ return cm::nullopt;
}
copyFileErrorMessage = emsg.str();
}
@@ -1122,7 +1123,15 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage);
}
}
- return res == 0;
+
+ cmTryCompileResult result;
+ result.SourceDirectory = sourceDirectory;
+ result.BinaryDirectory = this->BinaryDirectory;
+ result.Variable = *arguments.CompileResultVariable;
+ result.VariableCached = !arguments.NoCache;
+ result.Output = std::move(output);
+ result.ExitCode = res;
+ return result;
}
bool cmCoreTryCompile::IsTemporary(std::string const& path)
@@ -1263,3 +1272,20 @@ std::string cmCoreTryCompile::WriteSource(std::string const& filename,
file.close();
return filepath;
}
+
+void cmCoreTryCompile::WriteTryCompileEventFields(
+ cmConfigureLog& log, cmTryCompileResult const& compileResult)
+{
+#ifndef CMAKE_BOOTSTRAP
+ log.BeginObject("directories"_s);
+ log.WriteValue("source"_s, compileResult.SourceDirectory);
+ log.WriteValue("binary"_s, compileResult.BinaryDirectory);
+ log.EndObject();
+ log.BeginObject("buildResult"_s);
+ log.WriteValue("variable"_s, compileResult.Variable);
+ log.WriteValue("cached"_s, compileResult.VariableCached);
+ log.WriteLiteralTextBlock("stdout"_s, compileResult.Output);
+ log.WriteValue("exitCode"_s, compileResult.ExitCode);
+ log.EndObject();
+#endif
+}
diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h
index 3e1e12c..6d29586 100644
--- a/Source/cmCoreTryCompile.h
+++ b/Source/cmCoreTryCompile.h
@@ -14,10 +14,23 @@
#include "cmArgumentParserTypes.h"
#include "cmStateTypes.h"
+class cmConfigureLog;
class cmMakefile;
template <typename Iter>
class cmRange;
+struct cmTryCompileResult
+{
+ std::string SourceDirectory;
+ std::string BinaryDirectory;
+
+ bool VariableCached = true;
+ std::string Variable;
+
+ std::string Output;
+ int ExitCode = 1;
+};
+
/** \class cmCoreTryCompile
* \brief Base class for cmTryCompileCommand and cmTryRunCommand
*
@@ -80,8 +93,8 @@ public:
* This function requires at least two \p arguments and will crash if given
* fewer.
*/
- bool TryCompileCode(Arguments& arguments,
- cmStateEnums::TargetType targetType);
+ cm::optional<cmTryCompileResult> TryCompileCode(
+ Arguments& arguments, cmStateEnums::TargetType targetType);
/**
* Returns \c true if \p path resides within a CMake temporary directory,
@@ -103,6 +116,9 @@ public:
*/
void FindOutputFile(const std::string& targetName);
+ static void WriteTryCompileEventFields(
+ cmConfigureLog& log, cmTryCompileResult const& compileResult);
+
std::string BinaryDirectory;
std::string OutputFile;
std::string FindErrorMessage;
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
index a2c4ce1..eff21cc 100644
--- a/Source/cmTryCompileCommand.cxx
+++ b/Source/cmTryCompileCommand.cxx
@@ -2,6 +2,9 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTryCompileCommand.h"
+#include <cm/optional>
+
+#include "cmConfigureLog.h"
#include "cmCoreTryCompile.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
@@ -13,6 +16,23 @@
#include "cmValue.h"
#include "cmake.h"
+namespace {
+#ifndef CMAKE_BOOTSTRAP
+void WriteTryCompileEvent(cmConfigureLog& log, cmMakefile const& mf,
+ cmTryCompileResult const& compileResult)
+{
+ static const std::vector<unsigned long> LogVersionsWithTryCompileV1{ 1 };
+
+ if (log.IsAnyLogVersionEnabled(LogVersionsWithTryCompileV1)) {
+ log.BeginEvent("try_compile-v1");
+ log.WriteBacktrace(mf);
+ cmCoreTryCompile::WriteTryCompileEventFields(log, compileResult);
+ log.EndEvent();
+ }
+}
+#endif
+}
+
bool cmTryCompileCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -59,7 +79,15 @@ bool cmTryCompileCommand(std::vector<std::string> const& args,
if (!arguments) {
return true;
}
- tc.TryCompileCode(arguments, targetType);
+
+ if (cm::optional<cmTryCompileResult> compileResult =
+ tc.TryCompileCode(arguments, targetType)) {
+#ifndef CMAKE_BOOTSTRAP
+ if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) {
+ WriteTryCompileEvent(*log, mf, *compileResult);
+ }
+#endif
+ }
// if They specified clean then we clean up what we can
if (tc.SrcFileSignature) {
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index 1e81195..63e4478 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -3,12 +3,15 @@
#include "cmTryRunCommand.h"
#include <cstdio>
+#include <stdexcept>
#include <cm/optional>
+#include <cmext/string_view>
#include "cmsys/FStream.hxx"
#include "cmArgumentParserTypes.h"
+#include "cmConfigureLog.h"
#include "cmCoreTryCompile.h"
#include "cmDuration.h"
#include "cmExecutionStatus.h"
@@ -23,6 +26,48 @@
#include "cmake.h"
namespace {
+struct cmTryRunResult
+{
+ bool VariableCached = true;
+ std::string Variable;
+ cm::optional<std::string> Stdout;
+ cm::optional<std::string> Stderr;
+ cm::optional<std::string> ExitCode;
+};
+
+#ifndef CMAKE_BOOTSTRAP
+void WriteTryRunEvent(cmConfigureLog& log, cmMakefile const& mf,
+ cmTryCompileResult const& compileResult,
+ cmTryRunResult const& runResult)
+{
+ static const std::vector<unsigned long> LogVersionsWithTryRunV1{ 1 };
+
+ if (log.IsAnyLogVersionEnabled(LogVersionsWithTryRunV1)) {
+ log.BeginEvent("try_run-v1");
+ log.WriteBacktrace(mf);
+ cmCoreTryCompile::WriteTryCompileEventFields(log, compileResult);
+
+ log.BeginObject("runResult"_s);
+ log.WriteValue("variable"_s, runResult.Variable);
+ log.WriteValue("cached"_s, runResult.VariableCached);
+ if (runResult.Stdout) {
+ log.WriteLiteralTextBlock("stdout"_s, *runResult.Stdout);
+ }
+ if (runResult.Stderr) {
+ log.WriteLiteralTextBlock("stderr"_s, *runResult.Stderr);
+ }
+ if (runResult.ExitCode) {
+ try {
+ log.WriteValue("exitCode"_s, std::stoi(*runResult.ExitCode));
+ } catch (std::invalid_argument const&) {
+ log.WriteValue("exitCode"_s, *runResult.ExitCode);
+ }
+ }
+ log.EndObject();
+ log.EndEvent();
+ }
+}
+#endif
class TryRunCommandImpl : public cmCoreTryCompile
{
@@ -96,23 +141,35 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
}
bool captureRunOutput = false;
- bool captureRunOutputStdOutErr = false;
if (arguments.OutputVariable) {
captureRunOutput = true;
} else if (arguments.CompileOutputVariable) {
arguments.OutputVariable = arguments.CompileOutputVariable;
}
- if (arguments.RunOutputStdOutVariable || arguments.RunOutputStdErrVariable) {
- captureRunOutputStdOutErr = true;
- } else if (arguments.RunOutputVariable) {
- captureRunOutput = true;
+
+ // Capture the split output for the configure log unless the caller
+ // requests combined output to be captured by a variable.
+ bool captureRunOutputStdOutErr = true;
+ if (!arguments.RunOutputStdOutVariable &&
+ !arguments.RunOutputStdErrVariable) {
+ if (arguments.RunOutputVariable) {
+ captureRunOutput = true;
+ captureRunOutputStdOutErr = false;
+ } else if (arguments.OutputVariable) {
+ captureRunOutputStdOutErr = false;
+ }
}
// do the try compile
- bool compiled = this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE);
+ cm::optional<cmTryCompileResult> compileResult =
+ this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE);
+
+ cmTryRunResult runResult;
+ runResult.Variable = this->RunResultVariable;
+ runResult.VariableCached = !arguments.NoCache;
// now try running the command if it compiled
- if (compiled) {
+ if (compileResult && compileResult->ExitCode == 0) {
if (this->OutputFile.empty()) {
cmSystemTools::Error(this->FindErrorMessage);
} else {
@@ -131,22 +188,26 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
runArgs, *arguments.SourceDirectoryOrFile,
*arguments.CompileResultVariable,
captureRunOutput ? &runOutputContents : nullptr,
- captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
- ? &runOutputStdOutContents
- : nullptr,
- captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
- ? &runOutputStdErrContents
- : nullptr);
+ captureRunOutputStdOutErr ? &runOutputStdOutContents : nullptr,
+ captureRunOutputStdOutErr ? &runOutputStdErrContents : nullptr);
} else {
this->RunExecutable(
runArgs, arguments.RunWorkingDirectory,
captureRunOutput ? &runOutputContents : nullptr,
- captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
- ? &runOutputStdOutContents
- : nullptr,
- captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
- ? &runOutputStdErrContents
- : nullptr);
+ captureRunOutputStdOutErr ? &runOutputStdOutContents : nullptr,
+ captureRunOutputStdOutErr ? &runOutputStdErrContents : nullptr);
+ }
+
+ if (captureRunOutputStdOutErr) {
+ runResult.Stdout = runOutputStdOutContents;
+ runResult.Stderr = runOutputStdErrContents;
+ } else {
+ runResult.Stdout = runOutputContents;
+ }
+
+ if (cmValue ec =
+ this->Makefile->GetDefinition(this->RunResultVariable)) {
+ runResult.ExitCode = *ec;
}
// now put the output into the variables
@@ -177,6 +238,15 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
}
}
+#ifndef CMAKE_BOOTSTRAP
+ if (compileResult) {
+ cmMakefile const& mf = *(this->Makefile);
+ if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) {
+ WriteTryRunEvent(*log, mf, *compileResult, runResult);
+ }
+ }
+#endif
+
// if we created a directory etc, then cleanup after ourselves
if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) {
this->CleanupFiles(this->BinaryDirectory);
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index befcb55..ee63909 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -70,6 +70,7 @@
# include <cm3p/curl/curl.h>
# include <cm3p/json/writer.h>
+# include "cmConfigureLog.h"
# include "cmFileAPI.h"
# include "cmGraphVizWriter.h"
# include "cmVariableWatch.h"
@@ -2423,10 +2424,22 @@ int cmake::ActualConfigure()
#if !defined(CMAKE_BOOTSTRAP)
this->FileAPI = cm::make_unique<cmFileAPI>(this);
this->FileAPI->ReadQueries();
+
+ if (!this->GetIsInTryCompile()) {
+ this->TruncateOutputLog("CMakeConfigureLog.yaml");
+ this->ConfigureLog = cm::make_unique<cmConfigureLog>(
+ cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles"_s),
+ std::vector<unsigned long>());
+ }
#endif
// actually do the configure
this->GlobalGenerator->Configure();
+
+#if !defined(CMAKE_BOOTSTRAP)
+ this->ConfigureLog.reset();
+#endif
+
// Before saving the cache
// if the project did not define one of the entries below, add them now
// so users can edit the values in the cache:
diff --git a/Source/cmake.h b/Source/cmake.h
index 325c0c5..10db87d 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -37,6 +37,7 @@
# include "cmMakefileProfilingData.h"
#endif
+class cmConfigureLog;
class cmExternalMakefileProjectGeneratorFactory;
class cmFileAPI;
class cmFileTimeCache;
@@ -521,6 +522,10 @@ public:
void SetTraceFile(std::string const& file);
void PrintTraceFormatVersion();
+#ifndef CMAKE_BOOTSTRAP
+ cmConfigureLog* GetConfigureLog() const { return this->ConfigureLog.get(); }
+#endif
+
//! Use trace from another ::cmake instance.
void SetTraceRedirect(cmake* other);
@@ -714,6 +719,9 @@ private:
TraceFormat TraceFormatVar = TRACE_HUMAN;
cmGeneratedFileStream TraceFile;
cmake* TraceRedirect = nullptr;
+#ifndef CMAKE_BOOTSTRAP
+ std::unique_ptr<cmConfigureLog> ConfigureLog;
+#endif
bool WarnUninitialized = false;
bool WarnUnusedCli = true;
bool CheckSystemVars = false;
diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index cc754e8..54d7eb5 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -33,18 +33,18 @@ function(run_cmake test)
set(platform_name msys)
endif()
- foreach(o IN ITEMS out err)
- if(RunCMake-std${o}-file AND EXISTS ${top_src}/${RunCMake-std${o}-file})
- file(READ ${top_src}/${RunCMake-std${o}-file} expect_std${o})
- string(REGEX REPLACE "\n+$" "" expect_std${o} "${expect_std${o}}")
- elseif(EXISTS ${top_src}/${test}-std${o}-${platform_name}.txt)
- file(READ ${top_src}/${test}-std${o}-${platform_name}.txt expect_std${o})
- string(REGEX REPLACE "\n+$" "" expect_std${o} "${expect_std${o}}")
- elseif(EXISTS ${top_src}/${test}-std${o}.txt)
- file(READ ${top_src}/${test}-std${o}.txt expect_std${o})
- string(REGEX REPLACE "\n+$" "" expect_std${o} "${expect_std${o}}")
+ foreach(o IN ITEMS stdout stderr config)
+ if(RunCMake-${o}-file AND EXISTS ${top_src}/${RunCMake-${o}-file})
+ file(READ ${top_src}/${RunCMake-${o}-file} expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
+ elseif(EXISTS ${top_src}/${test}-${o}-${platform_name}.txt)
+ file(READ ${top_src}/${test}-${o}-${platform_name}.txt expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
+ elseif(EXISTS ${top_src}/${test}-${o}.txt)
+ file(READ ${top_src}/${test}-${o}.txt expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
else()
- unset(expect_std${o})
+ unset(expect_${o})
endif()
endforeach()
if (NOT expect_stderr)
@@ -144,6 +144,12 @@ function(run_cmake test)
if(NOT "${actual_result}" MATCHES "${expect_result}")
string(APPEND msg "Result is [${actual_result}], not [${expect_result}].\n")
endif()
+ set(config_file "${RunCMake_TEST_COMMAND_WORKING_DIRECTORY}/CMakeFiles/CMakeConfigureLog.yaml")
+ if(EXISTS "${config_file}")
+ file(READ "${config_file}" actual_config)
+ else()
+ set(actual_config "")
+ endif()
# Special case: remove ninja no-op line from stderr, but not stdout.
# Test cases that look for it should use RunCMake_TEST_OUTPUT_MERGE.
@@ -180,17 +186,13 @@ function(run_cmake test)
"|[^\n]*Bullseye Testing Technology"
")[^\n]*\n)+"
)
- foreach(o IN ITEMS out err)
- string(REGEX REPLACE "\r\n" "\n" actual_std${o} "${actual_std${o}}")
- string(REGEX REPLACE "${ignore_line_regex}" "\\1" actual_std${o} "${actual_std${o}}")
- string(REGEX REPLACE "\n+$" "" actual_std${o} "${actual_std${o}}")
- set(expect_${o} "")
- if(DEFINED expect_std${o})
- if(NOT "${actual_std${o}}" MATCHES "${expect_std${o}}")
- string(REGEX REPLACE "\n" "\n expect-${o}> " expect_${o}
- " expect-${o}> ${expect_std${o}}")
- set(expect_${o} "Expected std${o} to match:\n${expect_${o}}\n")
- string(APPEND msg "std${o} does not match that expected.\n")
+ foreach(o IN ITEMS stdout stderr config)
+ string(REGEX REPLACE "\r\n" "\n" actual_${o} "${actual_${o}}")
+ string(REGEX REPLACE "${ignore_line_regex}" "\\1" actual_${o} "${actual_${o}}")
+ string(REGEX REPLACE "\n+$" "" actual_${o} "${actual_${o}}")
+ if(DEFINED expect_${o})
+ if(NOT "${actual_${o}}" MATCHES "${expect_${o}}")
+ string(APPEND msg "${o} does not match that expected.\n")
endif()
endif()
endforeach()
@@ -215,15 +217,17 @@ function(run_cmake test)
string(APPEND msg "Command was:\n command> ${command}\n")
endif()
if(msg)
- string(REGEX REPLACE "\n" "\n actual-out> " actual_out " actual-out> ${actual_stdout}")
- string(REGEX REPLACE "\n" "\n actual-err> " actual_err " actual-err> ${actual_stderr}")
- message(SEND_ERROR "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - FAILED:\n"
- "${msg}"
- "${expect_out}"
- "Actual stdout:\n${actual_out}\n"
- "${expect_err}"
- "Actual stderr:\n${actual_err}\n"
- )
+ foreach(o IN ITEMS stdout stderr config)
+ if(DEFINED expect_${o})
+ string(REGEX REPLACE "\n" "\n expect-${o}> " expect_${o} " expect-${o}> ${expect_${o}}")
+ string(APPEND msg "Expected ${o} to match:\n${expect_${o}}\n")
+ endif()
+ if(NOT o STREQUAL "config" OR DEFINED expect_${o})
+ string(REGEX REPLACE "\n" "\n actual-${o}> " actual_${o} " actual-${o}> ${actual_${o}}")
+ string(APPEND msg "Actual ${o}:\n${actual_${o}}\n")
+ endif()
+ endforeach()
+ message(SEND_ERROR "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - FAILED:\n${msg}")
else()
message(STATUS "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - PASSED")
endif()
diff --git a/Tests/RunCMake/try_compile/Inspect-config.txt b/Tests/RunCMake/try_compile/Inspect-config.txt
new file mode 100644
index 0000000..47169cf
--- /dev/null
+++ b/Tests/RunCMake/try_compile/Inspect-config.txt
@@ -0,0 +1,34 @@
+^
+---
+events:
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "[^"]*/Modules/CMakeDetermineCompilerABI.cmake:[0-9]+ \(try_compile\)"
+ - "[^"]*/Modules/CMakeTestCCompiler.cmake:[0-9]+ \(CMAKE_DETERMINE_COMPILER_ABI\)"
+ - "Inspect.cmake:[0-9]+ \(enable_language\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_compile/Inspect-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ binary: "[^"]*/Tests/RunCMake/try_compile/Inspect-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ buildResult:
+ variable: "CMAKE_C_ABI_COMPILED"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "[^"]*/Modules/CMakeDetermineCompilerABI.cmake:[0-9]+ \(try_compile\)"
+ - "[^"]*/Modules/CMakeTestCXXCompiler.cmake:[0-9]+ \(CMAKE_DETERMINE_COMPILER_ABI\)"
+ - "Inspect.cmake:[0-9]+ \(enable_language\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_compile/Inspect-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ binary: "[^"]*/Tests/RunCMake/try_compile/Inspect-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ buildResult:
+ variable: "CMAKE_CXX_ABI_COMPILED"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+\.\.\.$
diff --git a/Tests/RunCMake/try_compile/SourceFromBadName-config.txt b/Tests/RunCMake/try_compile/SourceFromBadName-config.txt
new file mode 100644
index 0000000..10f3293
--- /dev/null
+++ b/Tests/RunCMake/try_compile/SourceFromBadName-config.txt
@@ -0,0 +1 @@
+^$
diff --git a/Tests/RunCMake/try_run/ConfigureLog-bad.c b/Tests/RunCMake/try_run/ConfigureLog-bad.c
new file mode 100644
index 0000000..6508ead
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog-bad.c
@@ -0,0 +1 @@
+#error "This does not compile!"
diff --git a/Tests/RunCMake/try_run/ConfigureLog-config.txt b/Tests/RunCMake/try_run/ConfigureLog-config.txt
new file mode 100644
index 0000000..602437e
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog-config.txt
@@ -0,0 +1,96 @@
+^
+---
+events:
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "[^"]*/Modules/CMakeDetermineCompilerABI.cmake:[0-9]+ \(try_compile\)"
+ - "[^"]*/Modules/CMakeTestCCompiler.cmake:[0-9]+ \(CMAKE_DETERMINE_COMPILER_ABI\)"
+ - "CMakeLists.txt:[0-9]+ \(project\)"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ buildResult:
+ variable: "CMAKE_C_ABI_COMPILED"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+ -
+ kind: "try_run-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_run\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: [1-9][0-9]*
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ -
+ kind: "try_run-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_run\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ stdout: \|
+ Output on stdout!
+ stderr: \|
+ Output, with backslash '\\\\', on stderr!
+ exitCode: 12
+ -
+ kind: "try_run-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_run\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ stdout: \|
+ Output, with backslash '\\\\', on stderr!
+ Output on stdout!
+ exitCode: 12
+ -
+ kind: "try_run-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_run\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ stdout: \|
+ Output on stdout!
+ stderr: \|
+ Output, with backslash '\\\\', on stderr!
+ exitCode: 12
+\.\.\.$
diff --git a/Tests/RunCMake/try_run/ConfigureLog-test.c b/Tests/RunCMake/try_run/ConfigureLog-test.c
new file mode 100644
index 0000000..6a8f125
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog-test.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stderr, "Output, with backslash '\\', on stderr!\n");
+ fflush(stderr); /* make output deterministic even if stderr is buffered */
+ fprintf(stdout, "Output on stdout!\n");
+ return 12;
+}
diff --git a/Tests/RunCMake/try_run/ConfigureLog.cmake b/Tests/RunCMake/try_run/ConfigureLog.cmake
new file mode 100644
index 0000000..4b5c7cb
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog.cmake
@@ -0,0 +1,18 @@
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-bad.c
+ )
+
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ )
+
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ RUN_OUTPUT_VARIABLE RUN_OUTPUT
+ )
+
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ RUN_OUTPUT_STDOUT_VARIABLE RUN_STDOUT
+ RUN_OUTPUT_STDERR_VARIABLE RUN_STDERR
+ )
diff --git a/Tests/RunCMake/try_run/RunCMakeTest.cmake b/Tests/RunCMake/try_run/RunCMakeTest.cmake
index dbea089..62e3caf 100644
--- a/Tests/RunCMake/try_run/RunCMakeTest.cmake
+++ b/Tests/RunCMake/try_run/RunCMakeTest.cmake
@@ -3,6 +3,7 @@ include(RunCMake)
run_cmake(BinDirEmpty)
run_cmake(BinDirRelative)
run_cmake(NoOutputVariable)
+run_cmake(ConfigureLog)
set(RunCMake_TEST_OPTIONS -Dtry_compile_DEFS=old_signature.cmake)
include(${RunCMake_SOURCE_DIR}/old_and_new_signature_tests.cmake)