mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 05:40:54 -06:00
Merge topic 'configure-log'
6c40e0b25eConfigureLog: Version individual events instead of the whole log048a02d5bbConfigureLog: Log try_compile and try_run checks746c776cafConfigureLog: Add infrastructure for structured configure event logginge8b8d82cbfTests: Generalize RunCMake expectation component names8d29a0bda6cmTryRunCommand: Factor out stdout/stderr capture conditionsfdda4095a3cmCoreTryCompile: Return more semantic information from compile step Acked-by: Kitware Robot <kwrobot@kitware.com> Tested-by: buildbot <buildbot@kitware.com> Merge-request: !8017
This commit is contained in:
@@ -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
|
||||
|
||||
254
Help/manual/cmake-configure-log.7.rst
Normal file
254
Help/manual/cmake-configure-log.7.rst
Normal file
@@ -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.
|
||||
5
Help/release/dev/configure-log.rst
Normal file
5
Help/release/dev/configure-log.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
Configure Log
|
||||
-------------
|
||||
|
||||
* CMake now writes a YAML log of configure-time checks.
|
||||
See the :manual:`cmake-configure-log(7)` manual.
|
||||
@@ -160,6 +160,8 @@ add_library(
|
||||
cmComputeLinkInformation.h
|
||||
cmComputeTargetDepends.h
|
||||
cmComputeTargetDepends.cxx
|
||||
cmConfigureLog.h
|
||||
cmConfigureLog.cxx
|
||||
cmConsoleBuf.h
|
||||
cmConsoleBuf.cxx
|
||||
cmConstStack.h
|
||||
|
||||
261
Source/cmConfigureLog.cxx
Normal file
261
Source/cmConfigureLog.cxx
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
68
Source/cmConfigureLog.h
Normal file
68
Source/cmConfigureLog.h
Normal file
@@ -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);
|
||||
};
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
34
Tests/RunCMake/try_compile/Inspect-config.txt
Normal file
34
Tests/RunCMake/try_compile/Inspect-config.txt
Normal file
@@ -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
|
||||
\.\.\.$
|
||||
1
Tests/RunCMake/try_compile/SourceFromBadName-config.txt
Normal file
1
Tests/RunCMake/try_compile/SourceFromBadName-config.txt
Normal file
@@ -0,0 +1 @@
|
||||
^$
|
||||
1
Tests/RunCMake/try_run/ConfigureLog-bad.c
Normal file
1
Tests/RunCMake/try_run/ConfigureLog-bad.c
Normal file
@@ -0,0 +1 @@
|
||||
#error "This does not compile!"
|
||||
96
Tests/RunCMake/try_run/ConfigureLog-config.txt
Normal file
96
Tests/RunCMake/try_run/ConfigureLog-config.txt
Normal file
@@ -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
|
||||
\.\.\.$
|
||||
9
Tests/RunCMake/try_run/ConfigureLog-test.c
Normal file
9
Tests/RunCMake/try_run/ConfigureLog-test.c
Normal file
@@ -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;
|
||||
}
|
||||
18
Tests/RunCMake/try_run/ConfigureLog.cmake
Normal file
18
Tests/RunCMake/try_run/ConfigureLog.cmake
Normal file
@@ -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
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user