ConfigureLog: Log try_compile and try_run checks

Add configure log events for `try_compile` and `try_run` results.

Issue: #23200
This commit is contained in:
Matthew Woehlke 2022-11-23 17:02:22 -05:00 committed by Brad King
parent 746c776caf
commit 048a02d5bb
12 changed files with 441 additions and 15 deletions

View File

@ -43,10 +43,10 @@ step finished normally, ends with a ``...`` document marker line:
minor: 0
events:
-
kind: "..."
kind: "try_compile"
# (other fields omitted)
-
kind: "..."
kind: "try_compile"
# (other fields omitted)
...
@ -99,4 +99,135 @@ The keys common to all events are:
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 event kind.
Additional mapping keys are specific to each event kind,
described below.
.. _`try_compile event`:
Event Kind ``try_compile``
--------------------------
The :command:`try_compile` command logs ``try_compile`` events.
A ``try_compile`` event is a YAML mapping:
.. code-block:: yaml
kind: "try_compile"
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`` 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.
A ``try_run`` event is a YAML mapping:
.. code-block:: yaml
kind: "try_run"
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`` mappings include those
documented by the `try_compile 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

@ -16,6 +16,7 @@
#include "cmsys/FStream.hxx"
#include "cmArgumentParser.h"
#include "cmConfigureLog.h"
#include "cmExportTryCompileFileGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@ -1124,6 +1125,11 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
}
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;
}
@ -1266,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,12 +14,20 @@
#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;
};
@ -108,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,19 @@
#include "cmValue.h"
#include "cmake.h"
namespace {
#ifndef CMAKE_BOOTSTRAP
void WriteTryCompileEvent(cmConfigureLog& log, cmMakefile const& mf,
cmTryCompileResult const& compileResult)
{
log.BeginEvent("try_compile");
log.WriteBacktrace(mf);
cmCoreTryCompile::WriteTryCompileEventFields(log, compileResult);
log.EndEvent();
}
#endif
}
bool cmTryCompileCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@ -59,7 +75,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,44 @@
#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)
{
log.BeginEvent("try_run");
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,24 +137,33 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
}
bool captureRunOutput = false;
bool captureRunOutputStdOut = false;
bool captureRunOutputStdErr = false;
if (arguments.OutputVariable) {
captureRunOutput = true;
} else if (arguments.CompileOutputVariable) {
arguments.OutputVariable = arguments.CompileOutputVariable;
}
if (arguments.RunOutputStdOutVariable || arguments.RunOutputStdErrVariable) {
captureRunOutputStdOut = arguments.RunOutputStdOutVariable.has_value();
captureRunOutputStdErr = arguments.RunOutputStdErrVariable.has_value();
} 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
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 (compileResult && compileResult->ExitCode == 0) {
if (this->OutputFile.empty()) {
@ -134,14 +184,26 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
runArgs, *arguments.SourceDirectoryOrFile,
*arguments.CompileResultVariable,
captureRunOutput ? &runOutputContents : nullptr,
captureRunOutputStdOut ? &runOutputStdOutContents : nullptr,
captureRunOutputStdErr ? &runOutputStdErrContents : nullptr);
captureRunOutputStdOutErr ? &runOutputStdOutContents : nullptr,
captureRunOutputStdOutErr ? &runOutputStdErrContents : nullptr);
} else {
this->RunExecutable(
runArgs, arguments.RunWorkingDirectory,
captureRunOutput ? &runOutputContents : nullptr,
captureRunOutputStdOut ? &runOutputStdOutContents : nullptr,
captureRunOutputStdErr ? &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
@ -172,6 +234,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

@ -0,0 +1,37 @@
^
---
version:
major: 1
minor: 0
events:
-
kind: "try_compile"
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"
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,99 @@
^
---
version:
major: 1
minor: 0
events:
-
kind: "try_compile"
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"
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"
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"
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"
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)