|
|
@@ -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;
|
|
|
+}
|
|
|
+
|
|
|
+ArgumentParser::Continue TryCompileCompileDefs(Arguments& args,
|
|
|
+ cm::string_view val)
|
|
|
+{
|
|
|
+ cmExpandList(val, args.CompileDefs);
|
|
|
+ return ArgumentParser::Continue::Yes;
|
|
|
}
|
|
|
|
|
|
-bool cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
|
|
|
+#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");
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
- 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;
|
|
|
-
|
|
|
- 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.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)) {
|
|
|
- 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)) {
|
|
|
+ if (!arguments.LangProps.empty()) {
|
|
|
+ this->Makefile->IssueMessage(
|
|
|
+ MessageType::FATAL_ERROR,
|
|
|
+ cmStrCat(arguments.LangProps.begin()->first,
|
|
|
+ " allowed only in source file signature."));
|
|
|
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);
|
|
|
}
|
|
|
}
|