cmCoreTryCompile: Port to cmArgumentParser
This commit is contained in:
parent
067ba3a2bd
commit
6b427d8da9
@ -2,6 +2,7 @@
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmCoreTryCompile.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <set>
|
||||
@ -13,12 +14,14 @@
|
||||
|
||||
#include "cmsys/Directory.hxx"
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
#include "cmExportTryCompileFileGenerator.h"
|
||||
#include "cmGlobalGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmOutputConverter.h"
|
||||
#include "cmPolicies.h"
|
||||
#include "cmRange.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
@ -28,142 +31,6 @@
|
||||
#include "cmake.h"
|
||||
|
||||
namespace {
|
||||
class LanguageStandardState
|
||||
{
|
||||
public:
|
||||
LanguageStandardState(std::string&& lang)
|
||||
: StandardFlag(lang + "_STANDARD")
|
||||
, RequiredFlag(lang + "_STANDARD_REQUIRED")
|
||||
, ExtensionFlag(lang + "_EXTENSIONS")
|
||||
{
|
||||
}
|
||||
|
||||
void Enabled(bool isEnabled) { this->IsEnabled = isEnabled; }
|
||||
|
||||
bool UpdateIfMatches(std::vector<std::string> const& argv, size_t& index)
|
||||
{
|
||||
bool updated = false;
|
||||
if (argv[index] == this->StandardFlag) {
|
||||
this->DidStandard = true;
|
||||
this->StandardValue = argv[++index];
|
||||
updated = true;
|
||||
} else if (argv[index] == this->RequiredFlag) {
|
||||
this->DidStandardRequired = true;
|
||||
this->RequiredValue = argv[++index];
|
||||
updated = true;
|
||||
} else if (argv[index] == this->ExtensionFlag) {
|
||||
this->DidExtensions = true;
|
||||
this->ExtensionValue = argv[++index];
|
||||
updated = true;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
bool Validate(cmMakefile* const makefile) const
|
||||
{
|
||||
if (this->DidStandard) {
|
||||
makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat(this->StandardFlag,
|
||||
" allowed only in source file signature."));
|
||||
return false;
|
||||
}
|
||||
if (this->DidStandardRequired) {
|
||||
makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat(this->RequiredFlag,
|
||||
" allowed only in source file signature."));
|
||||
return false;
|
||||
}
|
||||
if (this->DidExtensions) {
|
||||
makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat(this->ExtensionFlag,
|
||||
" allowed only in source file signature."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DidNone() const
|
||||
{
|
||||
return !this->DidStandard && !this->DidStandardRequired &&
|
||||
!this->DidExtensions;
|
||||
}
|
||||
|
||||
void LoadUnsetPropertyValues(cmMakefile* const makefile, bool honorStandard,
|
||||
bool warnCMP0067,
|
||||
std::vector<std::string>& warnCMP0067Variables)
|
||||
{
|
||||
if (!this->IsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lookupStdVar = [&](std::string const& var) -> std::string {
|
||||
std::string value = makefile->GetSafeDefinition(var);
|
||||
if (warnCMP0067 && !value.empty()) {
|
||||
value.clear();
|
||||
warnCMP0067Variables.emplace_back(var);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
if (honorStandard || warnCMP0067) {
|
||||
if (!this->DidStandard) {
|
||||
this->StandardValue =
|
||||
lookupStdVar(cmStrCat("CMAKE_", this->StandardFlag));
|
||||
}
|
||||
if (!this->DidStandardRequired) {
|
||||
this->RequiredValue =
|
||||
lookupStdVar(cmStrCat("CMAKE_", this->RequiredFlag));
|
||||
}
|
||||
if (!this->DidExtensions) {
|
||||
this->ExtensionValue =
|
||||
lookupStdVar(cmStrCat("CMAKE_", this->ExtensionFlag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteProperties(FILE* fout, std::string const& targetName) const
|
||||
{
|
||||
if (!this->IsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto writeProp = [&](std::string const& prop, std::string const& value) {
|
||||
fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n",
|
||||
targetName.c_str(),
|
||||
cmOutputConverter::EscapeForCMake(prop).c_str(),
|
||||
cmOutputConverter::EscapeForCMake(value).c_str());
|
||||
};
|
||||
|
||||
if (!this->StandardValue.empty()) {
|
||||
writeProp(this->StandardFlag, this->StandardValue);
|
||||
}
|
||||
if (!this->RequiredValue.empty()) {
|
||||
writeProp(this->RequiredFlag, this->RequiredValue);
|
||||
}
|
||||
if (!this->ExtensionValue.empty()) {
|
||||
writeProp(this->ExtensionFlag, this->ExtensionValue);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsEnabled = false;
|
||||
bool DidStandard = false;
|
||||
bool DidStandardRequired = false;
|
||||
bool DidExtensions = false;
|
||||
|
||||
std::string StandardFlag;
|
||||
std::string RequiredFlag;
|
||||
std::string ExtensionFlag;
|
||||
|
||||
std::string StandardValue;
|
||||
std::string RequiredValue;
|
||||
std::string ExtensionValue;
|
||||
};
|
||||
|
||||
constexpr size_t lang_property_start = 0;
|
||||
constexpr size_t lang_property_size = 4;
|
||||
constexpr size_t pie_property_start = 4;
|
||||
@ -233,12 +100,132 @@ std::set<std::string> const ghs_platform_vars{
|
||||
"GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME",
|
||||
"GHS_OS_DIR_OPTION"
|
||||
};
|
||||
using Arguments = cmCoreTryCompile::Arguments;
|
||||
|
||||
ArgumentParser::Continue TryCompileLangProp(Arguments& args,
|
||||
cm::string_view key,
|
||||
cm::string_view val)
|
||||
{
|
||||
args.LangProps[std::string(key)] = std::string(val);
|
||||
return ArgumentParser::Continue::No;
|
||||
}
|
||||
|
||||
bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
ArgumentParser::Continue TryCompileCompileDefs(Arguments& args,
|
||||
cm::string_view val)
|
||||
{
|
||||
cmExpandList(val, args.CompileDefs);
|
||||
return ArgumentParser::Continue::Yes;
|
||||
}
|
||||
|
||||
#define BIND_LANG_PROPS(lang) \
|
||||
Bind(#lang "_STANDARD"_s, TryCompileLangProp) \
|
||||
.Bind(#lang "_STANDARD_REQUIRED"_s, TryCompileLangProp) \
|
||||
.Bind(#lang "_EXTENSIONS"_s, TryCompileLangProp)
|
||||
|
||||
auto const TryCompileArgParser =
|
||||
cmArgumentParser<Arguments>{}
|
||||
.Bind(0, &Arguments::CompileResultVariable)
|
||||
.Bind(1, &Arguments::BinaryDirectory)
|
||||
.Bind(2, &Arguments::SourceDirectoryOrFile)
|
||||
.Bind(3, &Arguments::ProjectName)
|
||||
.Bind(4, &Arguments::TargetName)
|
||||
.Bind("SOURCES"_s, &Arguments::Sources)
|
||||
.Bind("CMAKE_FLAGS"_s, &Arguments::CMakeFlags)
|
||||
.Bind("COMPILE_DEFINITIONS"_s, TryCompileCompileDefs,
|
||||
ArgumentParser::ExpectAtLeast{ 0 })
|
||||
.Bind("LINK_LIBRARIES"_s, &Arguments::LinkLibraries)
|
||||
.Bind("LINK_OPTIONS"_s, &Arguments::LinkOptions)
|
||||
.Bind("__CMAKE_INTERNAL"_s, &Arguments::CMakeInternal)
|
||||
.Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable)
|
||||
.Bind("COPY_FILE"_s, &Arguments::CopyFileTo)
|
||||
.Bind("COPY_FILE_ERROR"_s, &Arguments::CopyFileError)
|
||||
.BIND_LANG_PROPS(C)
|
||||
.BIND_LANG_PROPS(CUDA)
|
||||
.BIND_LANG_PROPS(CXX)
|
||||
.BIND_LANG_PROPS(HIP)
|
||||
.BIND_LANG_PROPS(OBJC)
|
||||
.BIND_LANG_PROPS(OBJCXX)
|
||||
.Bind("COMPILE_OUTPUT_VARIABLE"_s, &Arguments::CompileOutputVariable)
|
||||
.Bind("RUN_OUTPUT_VARIABLE"_s, &Arguments::RunOutputVariable)
|
||||
.Bind("RUN_OUTPUT_STDOUT_VARIABLE"_s, &Arguments::RunOutputStdOutVariable)
|
||||
.Bind("RUN_OUTPUT_STDERR_VARIABLE"_s, &Arguments::RunOutputStdErrVariable)
|
||||
.Bind("WORKING_DIRECTORY"_s, &Arguments::RunWorkingDirectory)
|
||||
.Bind("ARGS"_s, &Arguments::RunArgs)
|
||||
/* keep semicolon on own line */;
|
||||
|
||||
#undef BIND_LANG_PROPS
|
||||
}
|
||||
|
||||
Arguments cmCoreTryCompile::ParseArgs(
|
||||
cmRange<std::vector<std::string>::const_iterator> args, bool isTryRun)
|
||||
{
|
||||
std::vector<std::string> unparsedArguments;
|
||||
auto arguments = TryCompileArgParser.Parse(args, &unparsedArguments, 0);
|
||||
if (!arguments.MaybeReportError(*(this->Makefile)) &&
|
||||
!unparsedArguments.empty()) {
|
||||
std::string m = "Unknown arguments:";
|
||||
for (const auto& i : unparsedArguments) {
|
||||
m = cmStrCat(m, "\n ", i, "\"");
|
||||
}
|
||||
this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m);
|
||||
}
|
||||
// For historical reasons, treat some empty-valued keyword
|
||||
// arguments as if they were not specified at all.
|
||||
if (arguments.OutputVariable && arguments.OutputVariable->empty()) {
|
||||
arguments.OutputVariable = cm::nullopt;
|
||||
}
|
||||
if (isTryRun) {
|
||||
if (arguments.CompileOutputVariable &&
|
||||
arguments.CompileOutputVariable->empty()) {
|
||||
arguments.CompileOutputVariable = cm::nullopt;
|
||||
}
|
||||
if (arguments.RunOutputVariable && arguments.RunOutputVariable->empty()) {
|
||||
arguments.RunOutputVariable = cm::nullopt;
|
||||
}
|
||||
if (arguments.RunOutputStdOutVariable &&
|
||||
arguments.RunOutputStdOutVariable->empty()) {
|
||||
arguments.RunOutputStdOutVariable = cm::nullopt;
|
||||
}
|
||||
if (arguments.RunOutputStdErrVariable &&
|
||||
arguments.RunOutputStdErrVariable->empty()) {
|
||||
arguments.RunOutputStdErrVariable = cm::nullopt;
|
||||
}
|
||||
if (arguments.RunWorkingDirectory &&
|
||||
arguments.RunWorkingDirectory->empty()) {
|
||||
arguments.RunWorkingDirectory = cm::nullopt;
|
||||
}
|
||||
} else {
|
||||
std::string tryRunArgs;
|
||||
if (arguments.CompileOutputVariable) {
|
||||
tryRunArgs = cmStrCat(tryRunArgs, " COMPILE_OUTPUT_VARIABLE\n");
|
||||
}
|
||||
if (arguments.RunOutputVariable) {
|
||||
tryRunArgs = cmStrCat(tryRunArgs, " RUN_OUTPUT_VARIABLE\n");
|
||||
}
|
||||
if (arguments.RunOutputStdOutVariable) {
|
||||
tryRunArgs = cmStrCat(tryRunArgs, " RUN_OUTPUT_STDOUT_VARIABLE\n");
|
||||
}
|
||||
if (arguments.RunOutputStdErrVariable) {
|
||||
tryRunArgs = cmStrCat(tryRunArgs, " RUN_OUTPUT_STDERR_VARIABLE\n");
|
||||
}
|
||||
if (arguments.RunWorkingDirectory) {
|
||||
tryRunArgs = cmStrCat(tryRunArgs, " WORKING_DIRECTORY\n");
|
||||
}
|
||||
if (arguments.RunArgs) {
|
||||
tryRunArgs = cmStrCat(tryRunArgs, " ARGS\n");
|
||||
}
|
||||
if (!tryRunArgs.empty()) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::AUTHOR_WARNING,
|
||||
cmStrCat("Ignoring try_run arguments for try_compile:\n", tryRunArgs));
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
|
||||
cmStateEnums::TargetType targetType)
|
||||
{
|
||||
std::string const& resultVar = argv[0];
|
||||
this->OutputFile.clear();
|
||||
// which signature were we called with ?
|
||||
this->SrcFileSignature = true;
|
||||
@ -246,82 +233,47 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
std::string sourceDirectory;
|
||||
std::string projectName;
|
||||
std::string targetName;
|
||||
std::vector<std::string> cmakeFlags(1, "CMAKE_FLAGS"); // fake argv[0]
|
||||
std::vector<std::string> compileDefs;
|
||||
std::string cmakeInternal;
|
||||
std::string outputVariable;
|
||||
std::string copyFile;
|
||||
std::string copyFileError;
|
||||
LanguageStandardState cState("C");
|
||||
LanguageStandardState cudaState("CUDA");
|
||||
LanguageStandardState cxxState("CXX");
|
||||
LanguageStandardState hipState("HIP");
|
||||
LanguageStandardState objcState("OBJC");
|
||||
LanguageStandardState objcxxState("OBJCXX");
|
||||
std::vector<std::string> targets;
|
||||
std::vector<std::string> linkOptions;
|
||||
std::string libsToLink = " ";
|
||||
bool useOldLinkLibs = true;
|
||||
bool didOutputVariable = false;
|
||||
bool didCopyFile = false;
|
||||
bool didCopyFileError = false;
|
||||
bool useSources = false;
|
||||
std::vector<std::string> sources;
|
||||
if (arguments.SourceDirectoryOrFile && arguments.ProjectName) {
|
||||
this->SrcFileSignature = false;
|
||||
sourceDirectory = *arguments.SourceDirectoryOrFile;
|
||||
projectName = *arguments.ProjectName;
|
||||
if (arguments.TargetName) {
|
||||
targetName = *arguments.TargetName;
|
||||
}
|
||||
} else {
|
||||
projectName = "CMAKE_TRY_COMPILE";
|
||||
/* Use a random file name to avoid rapid creation and deletion
|
||||
of the same executable name (some filesystems fail on that). */
|
||||
char targetNameBuf[64];
|
||||
snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x",
|
||||
cmSystemTools::RandomSeed() & 0xFFFFF);
|
||||
targetName = targetNameBuf;
|
||||
}
|
||||
|
||||
enum Doing
|
||||
{
|
||||
DoingNone,
|
||||
DoingCMakeFlags,
|
||||
DoingCompileDefinitions,
|
||||
DoingLinkOptions,
|
||||
DoingLinkLibraries,
|
||||
DoingOutputVariable,
|
||||
DoingCopyFile,
|
||||
DoingCopyFileError,
|
||||
DoingSources,
|
||||
DoingCMakeInternal
|
||||
};
|
||||
Doing doing = DoingNone;
|
||||
for (size_t i = 1; i < argv.size(); ++i) {
|
||||
if (argv[i] == "SOURCES") {
|
||||
useSources = true;
|
||||
doing = DoingSources;
|
||||
} else if (argv[i] == "CMAKE_FLAGS") {
|
||||
doing = DoingCMakeFlags;
|
||||
} else if (argv[i] == "COMPILE_DEFINITIONS") {
|
||||
doing = DoingCompileDefinitions;
|
||||
} else if (argv[i] == "LINK_OPTIONS") {
|
||||
doing = DoingLinkOptions;
|
||||
} else if (argv[i] == "LINK_LIBRARIES") {
|
||||
doing = DoingLinkLibraries;
|
||||
useOldLinkLibs = false;
|
||||
} else if (argv[i] == "OUTPUT_VARIABLE") {
|
||||
doing = DoingOutputVariable;
|
||||
didOutputVariable = true;
|
||||
} else if (argv[i] == "COPY_FILE") {
|
||||
doing = DoingCopyFile;
|
||||
didCopyFile = true;
|
||||
} else if (argv[i] == "COPY_FILE_ERROR") {
|
||||
doing = DoingCopyFileError;
|
||||
didCopyFileError = true;
|
||||
} else if (cState.UpdateIfMatches(argv, i) ||
|
||||
cxxState.UpdateIfMatches(argv, i) ||
|
||||
cudaState.UpdateIfMatches(argv, i) ||
|
||||
hipState.UpdateIfMatches(argv, i) ||
|
||||
objcState.UpdateIfMatches(argv, i) ||
|
||||
objcxxState.UpdateIfMatches(argv, i)) {
|
||||
continue;
|
||||
} else if (argv[i] == "__CMAKE_INTERNAL") {
|
||||
doing = DoingCMakeInternal;
|
||||
} else if (doing == DoingCMakeFlags) {
|
||||
cmakeFlags.emplace_back(argv[i]);
|
||||
} else if (doing == DoingCompileDefinitions) {
|
||||
cmExpandList(argv[i], compileDefs);
|
||||
} else if (doing == DoingLinkOptions) {
|
||||
linkOptions.emplace_back(argv[i]);
|
||||
} else if (doing == DoingLinkLibraries) {
|
||||
libsToLink += "\"" + cmTrimWhitespace(argv[i]) + "\" ";
|
||||
if (cmTarget* tgt = this->Makefile->FindTargetToUse(argv[i])) {
|
||||
if (arguments.BinaryDirectory && !arguments.BinaryDirectory->empty()) {
|
||||
if (!cmSystemTools::FileIsFullPath(*arguments.BinaryDirectory)) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("<bindir> is not an absolute path:\n '",
|
||||
*arguments.BinaryDirectory, "'"));
|
||||
return false;
|
||||
}
|
||||
this->BinaryDirectory = *arguments.BinaryDirectory;
|
||||
// compute the binary dir when TRY_COMPILE is called with a src file
|
||||
// signature
|
||||
if (this->SrcFileSignature) {
|
||||
this->BinaryDirectory += "/CMakeFiles/CMakeTmp";
|
||||
}
|
||||
} else {
|
||||
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
|
||||
"No <bindir> specified.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> targets;
|
||||
if (arguments.LinkLibraries) {
|
||||
for (std::string const& i : *arguments.LinkLibraries) {
|
||||
if (cmTarget* tgt = this->Makefile->FindTargetToUse(i)) {
|
||||
switch (tgt->GetType()) {
|
||||
case cmStateEnums::SHARED_LIBRARY:
|
||||
case cmStateEnums::STATIC_LIBRARY:
|
||||
@ -343,98 +295,33 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
return false;
|
||||
}
|
||||
if (tgt->IsImported()) {
|
||||
targets.emplace_back(argv[i]);
|
||||
targets.emplace_back(i);
|
||||
}
|
||||
}
|
||||
} else if (doing == DoingOutputVariable) {
|
||||
outputVariable = argv[i];
|
||||
doing = DoingNone;
|
||||
} else if (doing == DoingCopyFile) {
|
||||
copyFile = argv[i];
|
||||
doing = DoingNone;
|
||||
} else if (doing == DoingCopyFileError) {
|
||||
copyFileError = argv[i];
|
||||
doing = DoingNone;
|
||||
} else if (doing == DoingSources) {
|
||||
sources.emplace_back(argv[i]);
|
||||
} else if (doing == DoingCMakeInternal) {
|
||||
cmakeInternal = argv[i];
|
||||
doing = DoingNone;
|
||||
} else if (i == 1) {
|
||||
this->BinaryDirectory = argv[i];
|
||||
} else if (i == 2) {
|
||||
sourceDirectory = argv[i];
|
||||
} else if (i == 3) {
|
||||
this->SrcFileSignature = false;
|
||||
projectName = argv[i];
|
||||
} else if (i == 4 && !this->SrcFileSignature) {
|
||||
targetName = argv[i];
|
||||
} else {
|
||||
std::ostringstream m;
|
||||
m << "try_compile given unknown argument \"" << argv[i] << "\".";
|
||||
this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, m.str());
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->BinaryDirectory.empty()) {
|
||||
if (!cmSystemTools::FileIsFullPath(this->BinaryDirectory)) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("<bindir> is not an absolute path:\n '",
|
||||
this->BinaryDirectory, "'"));
|
||||
// Do not try to clean up the ill-specified directory.
|
||||
this->BinaryDirectory.clear();
|
||||
return false;
|
||||
}
|
||||
// compute the binary dir when TRY_COMPILE is called with a src file
|
||||
// signature
|
||||
if (this->SrcFileSignature) {
|
||||
this->BinaryDirectory += "/CMakeFiles/CMakeTmp";
|
||||
}
|
||||
} else {
|
||||
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
|
||||
"No <bindir> specified.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->SrcFileSignature) {
|
||||
projectName = "CMAKE_TRY_COMPILE";
|
||||
/* Use a random file name to avoid rapid creation and deletion
|
||||
of the same executable name (some filesystems fail on that). */
|
||||
char targetNameBuf[64];
|
||||
snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x",
|
||||
cmSystemTools::RandomSeed() & 0xFFFFF);
|
||||
targetName = targetNameBuf;
|
||||
}
|
||||
|
||||
if (didCopyFile && copyFile.empty()) {
|
||||
if (arguments.CopyFileTo && arguments.CopyFileTo->empty()) {
|
||||
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
|
||||
"COPY_FILE must be followed by a file path");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (didCopyFileError && copyFileError.empty()) {
|
||||
if (arguments.CopyFileError && arguments.CopyFileError->empty()) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"COPY_FILE_ERROR must be followed by a variable name");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (didCopyFileError && !didCopyFile) {
|
||||
if (arguments.CopyFileError && !arguments.CopyFileTo) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"COPY_FILE_ERROR may be used only with COPY_FILE");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (didOutputVariable && outputVariable.empty()) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"OUTPUT_VARIABLE must be followed by a variable name");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (useSources && sources.empty()) {
|
||||
if (arguments.Sources && arguments.Sources->empty()) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"SOURCES must be followed by at least one source file");
|
||||
@ -443,32 +330,20 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
|
||||
// only valid for srcfile signatures
|
||||
if (!this->SrcFileSignature) {
|
||||
if (!cState.Validate(this->Makefile)) {
|
||||
if (!arguments.LangProps.empty()) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat(arguments.LangProps.begin()->first,
|
||||
" allowed only in source file signature."));
|
||||
return false;
|
||||
}
|
||||
if (!cudaState.Validate(this->Makefile)) {
|
||||
return false;
|
||||
}
|
||||
if (!hipState.Validate(this->Makefile)) {
|
||||
return false;
|
||||
}
|
||||
if (!cxxState.Validate(this->Makefile)) {
|
||||
return false;
|
||||
}
|
||||
if (!objcState.Validate(this->Makefile)) {
|
||||
return false;
|
||||
}
|
||||
if (!objcxxState.Validate(this->Makefile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compileDefs.empty()) {
|
||||
if (!arguments.CompileDefs.empty()) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"COMPILE_DEFINITIONS specified on a srcdir type TRY_COMPILE");
|
||||
return false;
|
||||
}
|
||||
if (!copyFile.empty()) {
|
||||
if (arguments.CopyFileTo) {
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
"COPY_FILE specified on a srcdir type TRY_COMPILE");
|
||||
@ -495,8 +370,12 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
cmSystemTools::RemoveFile(ccFile);
|
||||
|
||||
// Choose sources.
|
||||
if (!useSources) {
|
||||
sources.emplace_back(argv[2]);
|
||||
std::vector<std::string> sources;
|
||||
if (arguments.Sources) {
|
||||
sources = std::move(*arguments.Sources);
|
||||
} else {
|
||||
// TODO: ensure SourceDirectoryOrFile has a value
|
||||
sources.emplace_back(*arguments.SourceDirectoryOrFile);
|
||||
}
|
||||
|
||||
// Detect languages to enable.
|
||||
@ -608,7 +487,7 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
}
|
||||
}
|
||||
fprintf(fout, "project(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
|
||||
if (cmakeInternal == "ABI") {
|
||||
if (arguments.CMakeInternal == "ABI") {
|
||||
// This is the ABI detection step, also used for implicit includes.
|
||||
// Erase any include_directories() calls from the toolchain file so
|
||||
// that we do not see them as implicit. Our ABI detection source
|
||||
@ -715,10 +594,10 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
fprintf(fout, "set(CMAKE_SUPPRESS_REGENERATION 1)\n");
|
||||
fprintf(fout, "link_directories(${LINK_DIRECTORIES})\n");
|
||||
// handle any compile flags we need to pass on
|
||||
if (!compileDefs.empty()) {
|
||||
if (!arguments.CompileDefs.empty()) {
|
||||
// Pass using bracket arguments to preserve content.
|
||||
fprintf(fout, "add_definitions([==[%s]==])\n",
|
||||
cmJoin(compileDefs, "]==] [==[").c_str());
|
||||
cmJoin(arguments.CompileDefs, "]==] [==[").c_str());
|
||||
}
|
||||
|
||||
if (!targets.empty()) {
|
||||
@ -782,18 +661,10 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
}
|
||||
fprintf(fout, ")\n");
|
||||
|
||||
cState.Enabled(testLangs.find("C") != testLangs.end());
|
||||
cxxState.Enabled(testLangs.find("CXX") != testLangs.end());
|
||||
cudaState.Enabled(testLangs.find("CUDA") != testLangs.end());
|
||||
hipState.Enabled(testLangs.find("HIP") != testLangs.end());
|
||||
objcState.Enabled(testLangs.find("OBJC") != testLangs.end());
|
||||
objcxxState.Enabled(testLangs.find("OBJCXX") != testLangs.end());
|
||||
|
||||
bool warnCMP0067 = false;
|
||||
bool honorStandard = true;
|
||||
|
||||
if (cState.DidNone() && cxxState.DidNone() && objcState.DidNone() &&
|
||||
objcxxState.DidNone() && cudaState.DidNone() && hipState.DidNone()) {
|
||||
if (arguments.LangProps.empty()) {
|
||||
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) {
|
||||
case cmPolicies::WARN:
|
||||
warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled(
|
||||
@ -818,18 +689,33 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
|
||||
std::vector<std::string> warnCMP0067Variables;
|
||||
|
||||
cState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067,
|
||||
warnCMP0067Variables);
|
||||
cxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
|
||||
warnCMP0067, warnCMP0067Variables);
|
||||
cudaState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
|
||||
warnCMP0067, warnCMP0067Variables);
|
||||
hipState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
|
||||
warnCMP0067, warnCMP0067Variables);
|
||||
objcState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
|
||||
warnCMP0067, warnCMP0067Variables);
|
||||
objcxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard,
|
||||
warnCMP0067, warnCMP0067Variables);
|
||||
if (honorStandard || warnCMP0067) {
|
||||
static std::array<std::string, 6> const possibleLangs{
|
||||
{ "C", "CXX", "CUDA", "HIP", "OBJC", "OBJCXX" }
|
||||
};
|
||||
static std::array<cm::string_view, 3> const langPropSuffixes{
|
||||
{ "_STANDARD"_s, "_STANDARD_REQUIRED"_s, "_EXTENSIONS"_s }
|
||||
};
|
||||
for (std::string const& lang : possibleLangs) {
|
||||
if (testLangs.find(lang) == testLangs.end()) {
|
||||
continue;
|
||||
}
|
||||
for (cm::string_view propSuffix : langPropSuffixes) {
|
||||
std::string langProp = cmStrCat(lang, propSuffix);
|
||||
if (!arguments.LangProps.count(langProp)) {
|
||||
std::string langPropVar = cmStrCat("CMAKE_"_s, langProp);
|
||||
std::string value = this->Makefile->GetSafeDefinition(langPropVar);
|
||||
if (warnCMP0067 && !value.empty()) {
|
||||
value.clear();
|
||||
warnCMP0067Variables.emplace_back(langPropVar);
|
||||
}
|
||||
if (!value.empty()) {
|
||||
arguments.LangProps[langProp] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!warnCMP0067Variables.empty()) {
|
||||
std::ostringstream w;
|
||||
@ -845,17 +731,20 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
|
||||
}
|
||||
|
||||
cState.WriteProperties(fout, targetName);
|
||||
cxxState.WriteProperties(fout, targetName);
|
||||
cudaState.WriteProperties(fout, targetName);
|
||||
hipState.WriteProperties(fout, targetName);
|
||||
objcState.WriteProperties(fout, targetName);
|
||||
objcxxState.WriteProperties(fout, targetName);
|
||||
for (auto const& p : arguments.LangProps) {
|
||||
if (p.second.empty()) {
|
||||
continue;
|
||||
}
|
||||
fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n",
|
||||
targetName.c_str(),
|
||||
cmOutputConverter::EscapeForCMake(p.first).c_str(),
|
||||
cmOutputConverter::EscapeForCMake(p.second).c_str());
|
||||
}
|
||||
|
||||
if (!linkOptions.empty()) {
|
||||
if (!arguments.LinkOptions.empty()) {
|
||||
std::vector<std::string> options;
|
||||
options.reserve(linkOptions.size());
|
||||
for (const auto& option : linkOptions) {
|
||||
options.reserve(arguments.LinkOptions.size());
|
||||
for (const auto& option : arguments.LinkOptions) {
|
||||
options.emplace_back(cmOutputConverter::EscapeForCMake(option));
|
||||
}
|
||||
|
||||
@ -869,12 +758,16 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
}
|
||||
}
|
||||
|
||||
if (useOldLinkLibs) {
|
||||
fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
|
||||
targetName.c_str());
|
||||
} else {
|
||||
if (arguments.LinkLibraries) {
|
||||
std::string libsToLink = " ";
|
||||
for (std::string const& i : *arguments.LinkLibraries) {
|
||||
libsToLink += "\"" + cmTrimWhitespace(i) + "\" ";
|
||||
}
|
||||
fprintf(fout, "target_link_libraries(%s %s)\n", targetName.c_str(),
|
||||
libsToLink.c_str());
|
||||
} else {
|
||||
fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
|
||||
targetName.c_str());
|
||||
}
|
||||
fclose(fout);
|
||||
}
|
||||
@ -965,13 +858,13 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES)) {
|
||||
vars.erase(kCMAKE_OSX_ARCHITECTURES);
|
||||
std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + *tcArchs;
|
||||
cmakeFlags.emplace_back(std::move(flag));
|
||||
arguments.CMakeFlags.emplace_back(std::move(flag));
|
||||
}
|
||||
|
||||
for (std::string const& var : vars) {
|
||||
if (cmValue val = this->Makefile->GetDefinition(var)) {
|
||||
std::string flag = "-D" + var + "=" + *val;
|
||||
cmakeFlags.emplace_back(std::move(flag));
|
||||
arguments.CMakeFlags.emplace_back(std::move(flag));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -981,7 +874,7 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
for (std::string const& var : ghs_platform_vars) {
|
||||
if (cmValue val = this->Makefile->GetDefinition(var)) {
|
||||
std::string flag = "-D" + var + "=" + "'" + *val + "'";
|
||||
cmakeFlags.emplace_back(std::move(flag));
|
||||
arguments.CMakeFlags.emplace_back(std::move(flag));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -992,26 +885,27 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
// actually do the try compile now that everything is setup
|
||||
int res = this->Makefile->TryCompile(
|
||||
sourceDirectory, this->BinaryDirectory, projectName, targetName,
|
||||
this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL, &cmakeFlags,
|
||||
output);
|
||||
this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL,
|
||||
&arguments.CMakeFlags, output);
|
||||
if (erroroc) {
|
||||
cmSystemTools::SetErrorOccurred();
|
||||
}
|
||||
|
||||
// set the result var to the return value to indicate success or failure
|
||||
this->Makefile->AddCacheDefinition(resultVar, (res == 0 ? "TRUE" : "FALSE"),
|
||||
"Result of TRY_COMPILE",
|
||||
cmStateEnums::INTERNAL);
|
||||
this->Makefile->AddCacheDefinition(
|
||||
*arguments.CompileResultVariable, (res == 0 ? "TRUE" : "FALSE"),
|
||||
"Result of TRY_COMPILE", cmStateEnums::INTERNAL);
|
||||
|
||||
if (!outputVariable.empty()) {
|
||||
this->Makefile->AddDefinition(outputVariable, output);
|
||||
if (arguments.OutputVariable) {
|
||||
this->Makefile->AddDefinition(*arguments.OutputVariable, output);
|
||||
}
|
||||
|
||||
if (this->SrcFileSignature) {
|
||||
std::string copyFileErrorMessage;
|
||||
this->FindOutputFile(targetName, targetType);
|
||||
|
||||
if ((res == 0) && !copyFile.empty()) {
|
||||
if ((res == 0) && arguments.CopyFileTo) {
|
||||
std::string const& copyFile = *arguments.CopyFileTo;
|
||||
if (this->OutputFile.empty() ||
|
||||
!cmSystemTools::CopyFileAlways(this->OutputFile, copyFile)) {
|
||||
std::ostringstream emsg;
|
||||
@ -1024,7 +918,7 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
if (!this->FindErrorMessage.empty()) {
|
||||
emsg << this->FindErrorMessage;
|
||||
}
|
||||
if (copyFileError.empty()) {
|
||||
if (!arguments.CopyFileError) {
|
||||
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
|
||||
return false;
|
||||
}
|
||||
@ -1032,7 +926,8 @@ bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
||||
}
|
||||
}
|
||||
|
||||
if (!copyFileError.empty()) {
|
||||
if (arguments.CopyFileError) {
|
||||
std::string const& copyFileError = *arguments.CopyFileError;
|
||||
this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage);
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,19 @@
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
#include "cmArgumentParserTypes.h"
|
||||
#include "cmStateTypes.h"
|
||||
|
||||
class cmMakefile;
|
||||
template <typename Iter>
|
||||
class cmRange;
|
||||
|
||||
/** \class cmCoreTryCompile
|
||||
* \brief Base class for cmTryCompileCommand and cmTryRunCommand
|
||||
@ -25,12 +32,46 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
struct Arguments : public ArgumentParser::ParseResult
|
||||
{
|
||||
cm::optional<std::string> CompileResultVariable;
|
||||
cm::optional<std::string> BinaryDirectory;
|
||||
cm::optional<std::string> SourceDirectoryOrFile;
|
||||
cm::optional<std::string> ProjectName;
|
||||
cm::optional<std::string> TargetName;
|
||||
cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> Sources;
|
||||
ArgumentParser::MaybeEmpty<std::vector<std::string>> CMakeFlags{
|
||||
1, "CMAKE_FLAGS"
|
||||
}; // fake argv[0]
|
||||
std::vector<std::string> CompileDefs;
|
||||
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
|
||||
LinkLibraries;
|
||||
ArgumentParser::MaybeEmpty<std::vector<std::string>> LinkOptions;
|
||||
std::map<std::string, std::string> LangProps;
|
||||
std::string CMakeInternal;
|
||||
cm::optional<std::string> OutputVariable;
|
||||
cm::optional<std::string> CopyFileTo;
|
||||
cm::optional<std::string> CopyFileError;
|
||||
|
||||
// Argument for try_run only.
|
||||
// Keep in sync with warnings in cmCoreTryCompile::ParseArgs.
|
||||
cm::optional<std::string> CompileOutputVariable;
|
||||
cm::optional<std::string> RunOutputVariable;
|
||||
cm::optional<std::string> RunOutputStdOutVariable;
|
||||
cm::optional<std::string> RunOutputStdErrVariable;
|
||||
cm::optional<std::string> RunWorkingDirectory;
|
||||
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> RunArgs;
|
||||
};
|
||||
|
||||
Arguments ParseArgs(cmRange<std::vector<std::string>::const_iterator> args,
|
||||
bool isTryRun);
|
||||
|
||||
/**
|
||||
* This is the core code for try compile. It is here so that other
|
||||
* commands, such as TryRun can access the same logic without
|
||||
* duplication.
|
||||
*/
|
||||
bool TryCompileCode(std::vector<std::string> const& argv,
|
||||
bool TryCompileCode(Arguments& arguments,
|
||||
cmStateEnums::TargetType targetType);
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmRange.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
@ -50,7 +51,12 @@ bool cmTryCompileCommand(std::vector<std::string> const& args,
|
||||
}
|
||||
|
||||
cmCoreTryCompile tc(&mf);
|
||||
tc.TryCompileCode(args, targetType);
|
||||
cmCoreTryCompile::Arguments arguments =
|
||||
tc.ParseArgs(cmMakeRange(args), false);
|
||||
if (!arguments) {
|
||||
return true;
|
||||
}
|
||||
tc.TryCompileCode(arguments, targetType);
|
||||
|
||||
// if They specified clean then we clean up what we can
|
||||
if (tc.SrcFileSignature) {
|
||||
|
@ -4,8 +4,11 @@
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmsys/FStream.hxx"
|
||||
|
||||
#include "cmArgumentParserTypes.h"
|
||||
#include "cmCoreTryCompile.h"
|
||||
#include "cmDuration.h"
|
||||
#include "cmExecutionStatus.h"
|
||||
@ -32,115 +35,35 @@ public:
|
||||
bool TryRunCode(std::vector<std::string> const& args);
|
||||
|
||||
void RunExecutable(const std::string& runArgs,
|
||||
cm::optional<std::string> const& workDir,
|
||||
std::string* runOutputContents,
|
||||
std::string* runOutputStdOutContents,
|
||||
std::string* runOutputStdErrContents);
|
||||
void DoNotRunExecutable(const std::string& runArgs,
|
||||
const std::string& srcFile,
|
||||
std::string const& compileResultVariable,
|
||||
std::string* runOutputContents,
|
||||
std::string* runOutputStdOutContents,
|
||||
std::string* runOutputStdErrContents);
|
||||
|
||||
std::string CompileResultVariable;
|
||||
std::string RunResultVariable;
|
||||
std::string OutputVariable;
|
||||
std::string RunOutputVariable;
|
||||
std::string RunOutputStdOutVariable;
|
||||
std::string RunOutputStdErrVariable;
|
||||
std::string CompileOutputVariable;
|
||||
std::string WorkingDirectory;
|
||||
};
|
||||
|
||||
bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
|
||||
{
|
||||
// build an arg list for TryCompile and extract the runArgs,
|
||||
std::vector<std::string> tryCompile;
|
||||
|
||||
this->CompileResultVariable.clear();
|
||||
this->RunResultVariable.clear();
|
||||
this->OutputVariable.clear();
|
||||
this->RunOutputVariable.clear();
|
||||
this->RunOutputStdOutVariable.clear();
|
||||
this->RunOutputStdErrVariable.clear();
|
||||
this->CompileOutputVariable.clear();
|
||||
|
||||
std::string runArgs;
|
||||
unsigned int i;
|
||||
for (i = 1; i < argv.size(); ++i) {
|
||||
if (argv[i] == "ARGS") {
|
||||
++i;
|
||||
while (i < argv.size() && argv[i] != "COMPILE_DEFINITIONS" &&
|
||||
argv[i] != "CMAKE_FLAGS" && argv[i] != "LINK_OPTIONS" &&
|
||||
argv[i] != "LINK_LIBRARIES") {
|
||||
runArgs += " ";
|
||||
runArgs += argv[i];
|
||||
++i;
|
||||
}
|
||||
if (i < argv.size()) {
|
||||
tryCompile.push_back(argv[i]);
|
||||
}
|
||||
} else {
|
||||
if (argv[i] == "OUTPUT_VARIABLE") {
|
||||
if (argv.size() <= (i + 1)) {
|
||||
cmSystemTools::Error(
|
||||
"OUTPUT_VARIABLE specified but there is no variable");
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
this->OutputVariable = argv[i];
|
||||
} else if (argv[i] == "RUN_OUTPUT_VARIABLE") {
|
||||
if (argv.size() <= (i + 1)) {
|
||||
cmSystemTools::Error(
|
||||
"RUN_OUTPUT_VARIABLE specified but there is no variable");
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
this->RunOutputVariable = argv[i];
|
||||
} else if (argv[i] == "RUN_OUTPUT_STDOUT_VARIABLE") {
|
||||
if (argv.size() <= (i + 1)) {
|
||||
cmSystemTools::Error(
|
||||
"RUN_OUTPUT_STDOUT_VARIABLE specified but there is no variable");
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
this->RunOutputStdOutVariable = argv[i];
|
||||
} else if (argv[i] == "RUN_OUTPUT_STDERR_VARIABLE") {
|
||||
if (argv.size() <= (i + 1)) {
|
||||
cmSystemTools::Error(
|
||||
"RUN_OUTPUT_STDERR_VARIABLE specified but there is no variable");
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
this->RunOutputStdErrVariable = argv[i];
|
||||
} else if (argv[i] == "COMPILE_OUTPUT_VARIABLE") {
|
||||
if (argv.size() <= (i + 1)) {
|
||||
cmSystemTools::Error(
|
||||
"COMPILE_OUTPUT_VARIABLE specified but there is no variable");
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
this->CompileOutputVariable = argv[i];
|
||||
} else if (argv[i] == "WORKING_DIRECTORY") {
|
||||
if (argv.size() <= (i + 1)) {
|
||||
cmSystemTools::Error(
|
||||
"WORKING_DIRECTORY specified but there is no variable");
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
this->WorkingDirectory = argv[i];
|
||||
} else {
|
||||
tryCompile.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
this->RunResultVariable = argv[0];
|
||||
cmCoreTryCompile::Arguments arguments =
|
||||
this->ParseArgs(cmMakeRange(argv).advance(1), true);
|
||||
if (!arguments) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// although they could be used together, don't allow it, because
|
||||
// using OUTPUT_VARIABLE makes crosscompiling harder
|
||||
if (!this->OutputVariable.empty() &&
|
||||
(!this->RunOutputVariable.empty() ||
|
||||
!this->CompileOutputVariable.empty() ||
|
||||
!this->RunOutputStdOutVariable.empty() ||
|
||||
!this->RunOutputStdErrVariable.empty())) {
|
||||
if (arguments.OutputVariable &&
|
||||
(arguments.CompileOutputVariable || arguments.RunOutputVariable ||
|
||||
arguments.RunOutputStdOutVariable ||
|
||||
arguments.RunOutputStdErrVariable)) {
|
||||
cmSystemTools::Error(
|
||||
"You cannot use OUTPUT_VARIABLE together with COMPILE_OUTPUT_VARIABLE "
|
||||
", RUN_OUTPUT_VARIABLE, RUN_OUTPUT_STDOUT_VARIABLE or "
|
||||
@ -151,9 +74,9 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!this->RunOutputStdOutVariable.empty() ||
|
||||
!RunOutputStdErrVariable.empty()) &&
|
||||
!this->RunOutputVariable.empty()) {
|
||||
if ((arguments.RunOutputStdOutVariable ||
|
||||
arguments.RunOutputStdErrVariable) &&
|
||||
arguments.RunOutputVariable) {
|
||||
cmSystemTools::Error(
|
||||
"You cannot use RUN_OUTPUT_STDOUT_VARIABLE or "
|
||||
"RUN_OUTPUT_STDERR_VARIABLE together "
|
||||
@ -162,43 +85,40 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->WorkingDirectory.empty()) {
|
||||
if (!cmSystemTools::MakeDirectory(this->WorkingDirectory)) {
|
||||
if (arguments.RunWorkingDirectory) {
|
||||
if (!cmSystemTools::MakeDirectory(*arguments.RunWorkingDirectory)) {
|
||||
cmSystemTools::Error(cmStrCat("Error creating working directory \"",
|
||||
this->WorkingDirectory, "\"."));
|
||||
*arguments.RunWorkingDirectory, "\"."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool captureRunOutput = false;
|
||||
bool captureRunOutputStdOutErr = false;
|
||||
if (!this->OutputVariable.empty()) {
|
||||
if (arguments.OutputVariable) {
|
||||
captureRunOutput = true;
|
||||
tryCompile.emplace_back("OUTPUT_VARIABLE");
|
||||
tryCompile.push_back(this->OutputVariable);
|
||||
} else if (arguments.CompileOutputVariable) {
|
||||
arguments.OutputVariable = arguments.CompileOutputVariable;
|
||||
}
|
||||
if (!this->CompileOutputVariable.empty()) {
|
||||
tryCompile.emplace_back("OUTPUT_VARIABLE");
|
||||
tryCompile.push_back(this->CompileOutputVariable);
|
||||
}
|
||||
if (!this->RunOutputStdOutVariable.empty() ||
|
||||
!RunOutputStdErrVariable.empty()) {
|
||||
if (arguments.RunOutputStdOutVariable || arguments.RunOutputStdErrVariable) {
|
||||
captureRunOutputStdOutErr = true;
|
||||
} else if (!this->RunOutputVariable.empty()) {
|
||||
} else if (arguments.RunOutputVariable) {
|
||||
captureRunOutput = true;
|
||||
}
|
||||
|
||||
this->RunResultVariable = argv[0];
|
||||
this->CompileResultVariable = argv[1];
|
||||
|
||||
// do the try compile
|
||||
bool compiled = this->TryCompileCode(tryCompile, cmStateEnums::EXECUTABLE);
|
||||
bool compiled = this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE);
|
||||
|
||||
// now try running the command if it compiled
|
||||
if (compiled) {
|
||||
if (this->OutputFile.empty()) {
|
||||
cmSystemTools::Error(this->FindErrorMessage);
|
||||
} else {
|
||||
std::string runArgs;
|
||||
if (arguments.RunArgs) {
|
||||
runArgs = cmStrCat(" ", cmJoin(*arguments.RunArgs, " "));
|
||||
}
|
||||
|
||||
// "run" it and capture the output
|
||||
std::string runOutputContents;
|
||||
std::string runOutputStdOutContents;
|
||||
@ -206,47 +126,51 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
|
||||
if (this->Makefile->IsOn("CMAKE_CROSSCOMPILING") &&
|
||||
!this->Makefile->IsDefinitionSet("CMAKE_CROSSCOMPILING_EMULATOR")) {
|
||||
this->DoNotRunExecutable(
|
||||
runArgs, argv[3], captureRunOutput ? &runOutputContents : nullptr,
|
||||
captureRunOutputStdOutErr && !RunOutputStdOutVariable.empty()
|
||||
runArgs, *arguments.SourceDirectoryOrFile,
|
||||
*arguments.CompileResultVariable,
|
||||
captureRunOutput ? &runOutputContents : nullptr,
|
||||
captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
|
||||
? &runOutputStdOutContents
|
||||
: nullptr,
|
||||
captureRunOutputStdOutErr && !RunOutputStdErrVariable.empty()
|
||||
captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
|
||||
? &runOutputStdErrContents
|
||||
: nullptr);
|
||||
} else {
|
||||
this->RunExecutable(
|
||||
runArgs, captureRunOutput ? &runOutputContents : nullptr,
|
||||
captureRunOutputStdOutErr && !RunOutputStdOutVariable.empty()
|
||||
runArgs, arguments.RunWorkingDirectory,
|
||||
captureRunOutput ? &runOutputContents : nullptr,
|
||||
captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
|
||||
? &runOutputStdOutContents
|
||||
: nullptr,
|
||||
captureRunOutputStdOutErr && !RunOutputStdErrVariable.empty()
|
||||
captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
|
||||
? &runOutputStdErrContents
|
||||
: nullptr);
|
||||
}
|
||||
|
||||
// now put the output into the variables
|
||||
if (!this->RunOutputVariable.empty()) {
|
||||
this->Makefile->AddDefinition(this->RunOutputVariable,
|
||||
if (arguments.RunOutputVariable) {
|
||||
this->Makefile->AddDefinition(*arguments.RunOutputVariable,
|
||||
runOutputContents);
|
||||
}
|
||||
if (!this->RunOutputStdOutVariable.empty()) {
|
||||
this->Makefile->AddDefinition(this->RunOutputStdOutVariable,
|
||||
if (arguments.RunOutputStdOutVariable) {
|
||||
this->Makefile->AddDefinition(*arguments.RunOutputStdOutVariable,
|
||||
runOutputStdOutContents);
|
||||
}
|
||||
if (!this->RunOutputStdErrVariable.empty()) {
|
||||
this->Makefile->AddDefinition(this->RunOutputStdErrVariable,
|
||||
if (arguments.RunOutputStdErrVariable) {
|
||||
this->Makefile->AddDefinition(*arguments.RunOutputStdErrVariable,
|
||||
runOutputStdErrContents);
|
||||
}
|
||||
|
||||
if (!this->OutputVariable.empty()) {
|
||||
if (arguments.OutputVariable && !arguments.CompileOutputVariable) {
|
||||
// if the TryCompileCore saved output in this outputVariable then
|
||||
// prepend that output to this output
|
||||
cmValue compileOutput =
|
||||
this->Makefile->GetDefinition(this->OutputVariable);
|
||||
this->Makefile->GetDefinition(*arguments.OutputVariable);
|
||||
if (compileOutput) {
|
||||
runOutputContents = *compileOutput + runOutputContents;
|
||||
}
|
||||
this->Makefile->AddDefinition(this->OutputVariable, runOutputContents);
|
||||
this->Makefile->AddDefinition(*arguments.OutputVariable,
|
||||
runOutputContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -259,6 +183,7 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
|
||||
}
|
||||
|
||||
void TryRunCommandImpl::RunExecutable(const std::string& runArgs,
|
||||
cm::optional<std::string> const& workDir,
|
||||
std::string* out, std::string* stdOut,
|
||||
std::string* stdErr)
|
||||
{
|
||||
@ -286,8 +211,8 @@ void TryRunCommandImpl::RunExecutable(const std::string& runArgs,
|
||||
bool worked = cmSystemTools::RunSingleCommand(
|
||||
finalCommand, stdOut || stdErr ? stdOut : out,
|
||||
stdOut || stdErr ? stdErr : out, &retVal,
|
||||
this->WorkingDirectory.empty() ? nullptr : this->WorkingDirectory.c_str(),
|
||||
cmSystemTools::OUTPUT_NONE, cmDuration::zero());
|
||||
workDir ? workDir->c_str() : nullptr, cmSystemTools::OUTPUT_NONE,
|
||||
cmDuration::zero());
|
||||
// set the run var
|
||||
char retChar[16];
|
||||
const char* retStr;
|
||||
@ -306,11 +231,10 @@ void TryRunCommandImpl::RunExecutable(const std::string& runArgs,
|
||||
executable, two cache variables are created which will hold the results
|
||||
the executable would have produced.
|
||||
*/
|
||||
void TryRunCommandImpl::DoNotRunExecutable(const std::string& runArgs,
|
||||
const std::string& srcFile,
|
||||
std::string* out,
|
||||
std::string* stdOut,
|
||||
std::string* stdErr)
|
||||
void TryRunCommandImpl::DoNotRunExecutable(
|
||||
const std::string& runArgs, const std::string& srcFile,
|
||||
std::string const& compileResultVariable, std::string* out,
|
||||
std::string* stdOut, std::string* stdErr)
|
||||
{
|
||||
// copy the executable out of the CMakeFiles/ directory, so it is not
|
||||
// removed at the end of try_run() and the user can run it manually
|
||||
@ -490,7 +414,7 @@ void TryRunCommandImpl::DoNotRunExecutable(const std::string& runArgs,
|
||||
}
|
||||
|
||||
comment += "The ";
|
||||
comment += this->CompileResultVariable;
|
||||
comment += compileResultVariable;
|
||||
comment += " variable holds the build result for this try_run().\n\n"
|
||||
"Source file : ";
|
||||
comment += srcFile + "\n";
|
||||
|
1
Tests/RunCMake/try_compile/NoCStandard-result.txt
Normal file
1
Tests/RunCMake/try_compile/NoCStandard-result.txt
Normal file
@ -0,0 +1 @@
|
||||
1
|
7
Tests/RunCMake/try_compile/NoCStandard-stderr.txt
Normal file
7
Tests/RunCMake/try_compile/NoCStandard-stderr.txt
Normal file
@ -0,0 +1,7 @@
|
||||
CMake Error at NoCStandard.cmake:1 \(try_compile\):
|
||||
Error after keyword "C_STANDARD":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
2
Tests/RunCMake/try_compile/NoCStandard.cmake
Normal file
2
Tests/RunCMake/try_compile/NoCStandard.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
try_compile(result ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src.c
|
||||
C_STANDARD)
|
@ -1,4 +1,7 @@
|
||||
CMake Error at NoCopyFile.cmake:1 \(try_compile\):
|
||||
COPY_FILE must be followed by a file path
|
||||
Error after keyword "COPY_FILE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -1,4 +1,7 @@
|
||||
CMake Error at NoCopyFile2.cmake:1 \(try_compile\):
|
||||
COPY_FILE must be followed by a file path
|
||||
Error after keyword "COPY_FILE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -1,4 +1,7 @@
|
||||
CMake Error at NoCopyFileError.cmake:1 \(try_compile\):
|
||||
COPY_FILE_ERROR must be followed by a variable name
|
||||
Error after keyword "COPY_FILE_ERROR":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -1,4 +1,7 @@
|
||||
CMake Error at NoOutputVariable.cmake:1 \(try_compile\):
|
||||
OUTPUT_VARIABLE must be followed by a variable name
|
||||
Error after keyword "OUTPUT_VARIABLE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -1,4 +1,7 @@
|
||||
CMake Error at NoOutputVariable2.cmake:1 \(try_compile\):
|
||||
OUTPUT_VARIABLE must be followed by a variable name
|
||||
Error after keyword "OUTPUT_VARIABLE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -1,4 +1,7 @@
|
||||
CMake Error at NoSources.cmake:1 \(try_compile\):
|
||||
SOURCES must be followed by at least one source file
|
||||
Error after keyword "SOURCES":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)
|
||||
|
@ -7,6 +7,7 @@ run_cmake(TwoArgs)
|
||||
run_cmake(NoCopyFile)
|
||||
run_cmake(NoCopyFile2)
|
||||
run_cmake(NoCopyFileError)
|
||||
run_cmake(NoCStandard)
|
||||
run_cmake(NoOutputVariable)
|
||||
run_cmake(NoOutputVariable2)
|
||||
run_cmake(NoSources)
|
||||
|
@ -1,71 +1,13 @@
|
||||
^CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "COMPILE_OUTPUT_VARIABLE".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "compOutputVar".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "RUN_OUTPUT_VARIABLE".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "runOutputVar".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "RUN_OUTPUT_STDOUT_VARIABLE".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "runOutputStdOutVar".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "RUN_OUTPUT_STDERR_VARIABLE".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "runOutputStdErrVar".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "WORKING_DIRECTORY".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "runWorkDir".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "ARGS".
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.
|
||||
+
|
||||
CMake Warning \(dev\) at TryRunArgs.cmake:[0-9]+ \(try_compile\):
|
||||
try_compile given unknown argument "runArgs".
|
||||
Ignoring try_run arguments for try_compile:
|
||||
|
||||
COMPILE_OUTPUT_VARIABLE
|
||||
RUN_OUTPUT_VARIABLE
|
||||
RUN_OUTPUT_STDOUT_VARIABLE
|
||||
RUN_OUTPUT_STDERR_VARIABLE
|
||||
WORKING_DIRECTORY
|
||||
ARGS
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers. Use -Wno-dev to suppress it.$
|
||||
|
@ -1,5 +1,7 @@
|
||||
^CMake Error: COMPILE_OUTPUT_VARIABLE specified but there is no variable
|
||||
CMake Error at NoCompileOutputVariable.cmake:[0-9]+ \(try_run\):
|
||||
try_run unknown error.
|
||||
^CMake Error at NoCompileOutputVariable.cmake:[0-9]+ \(try_run\):
|
||||
Error after keyword "COMPILE_OUTPUT_VARIABLE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)$
|
||||
|
@ -1,5 +1,7 @@
|
||||
^CMake Error: OUTPUT_VARIABLE specified but there is no variable
|
||||
CMake Error at NoOutputVariable.cmake:[0-9]+ \(try_run\):
|
||||
try_run unknown error.
|
||||
^CMake Error at NoOutputVariable.cmake:[0-9]+ \(try_run\):
|
||||
Error after keyword "OUTPUT_VARIABLE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)$
|
||||
|
@ -1,5 +1,7 @@
|
||||
^CMake Error: RUN_OUTPUT_VARIABLE specified but there is no variable
|
||||
CMake Error at NoRunOutputVariable.cmake:[0-9]+ \(try_run\):
|
||||
try_run unknown error.
|
||||
^CMake Error at NoRunOutputVariable.cmake:[0-9]+ \(try_run\):
|
||||
Error after keyword "RUN_OUTPUT_VARIABLE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)$
|
||||
|
@ -1,5 +1,7 @@
|
||||
^CMake Error: RUN_OUTPUT_STDERR_VARIABLE specified but there is no variable
|
||||
CMake Error at NoRunStdErrVariable.cmake:1 \(try_run\):
|
||||
try_run unknown error.
|
||||
^CMake Error at NoRunStdErrVariable.cmake:1 \(try_run\):
|
||||
Error after keyword "RUN_OUTPUT_STDERR_VARIABLE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)$
|
||||
|
@ -1,5 +1,7 @@
|
||||
^CMake Error: RUN_OUTPUT_STDOUT_VARIABLE specified but there is no variable
|
||||
CMake Error at NoRunStdOutVariable.cmake:1 \(try_run\):
|
||||
try_run unknown error.
|
||||
^CMake Error at NoRunStdOutVariable.cmake:1 \(try_run\):
|
||||
Error after keyword "RUN_OUTPUT_STDOUT_VARIABLE":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:3 \(include\)$
|
||||
|
@ -1,5 +1,7 @@
|
||||
^CMake Error: WORKING_DIRECTORY specified but there is no variable
|
||||
CMake Error at NoWorkingDirectory.cmake:[0-9]+ \(try_run\):
|
||||
try_run unknown error.
|
||||
^CMake Error at NoWorkingDirectory.cmake:[0-9]+ \(try_run\):
|
||||
Error after keyword "WORKING_DIRECTORY":
|
||||
|
||||
missing required value
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)$
|
||||
|
Loading…
Reference in New Issue
Block a user