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
+2
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
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
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);
};
+52 -26
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
}
+18 -2
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;
+29 -1
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) {
+89 -19
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);
+13
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:
+8
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;