Merge topic 'configure-log'

6c40e0b25e ConfigureLog: Version individual events instead of the whole log
048a02d5bb ConfigureLog: Log try_compile and try_run checks
746c776caf ConfigureLog: Add infrastructure for structured configure event logging
e8b8d82cbf Tests: Generalize RunCMake expectation component names
8d29a0bda6 cmTryRunCommand: Factor out stdout/stderr capture conditions
fdda4095a3 cmCoreTryCompile: 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:
Brad King
2022-12-17 13:44:36 +00:00
committed by Kitware Robot
20 changed files with 995 additions and 79 deletions

View File

@@ -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

View 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.

View 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.

View File

@@ -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
View 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
View 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);
};

View File

@@ -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
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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:

View File

@@ -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;

View File

@@ -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()

View 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
\.\.\.$

View File

@@ -0,0 +1 @@
^$

View File

@@ -0,0 +1 @@
#error "This does not compile!"

View 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
\.\.\.$

View 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;
}

View 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
)

View File

@@ -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)