summaryrefslogtreecommitdiffstats
path: root/Source/cmCoreTryCompile.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmCoreTryCompile.cxx')
-rw-r--r--Source/cmCoreTryCompile.cxx124
1 files changed, 116 insertions, 8 deletions
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 7e7f8d2..f40b3e9 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -153,7 +153,7 @@ auto const TryCompileBaseArgParser =
.Bind("__CMAKE_INTERNAL"_s, &Arguments::CMakeInternal)
/* keep semicolon on own line */;
-auto const TryCompileBaseNonProjectArgParser =
+auto const TryCompileBaseSourcesArgParser =
cmArgumentParser<Arguments>{ TryCompileBaseArgParser }
.Bind("SOURCES"_s, &Arguments::Sources)
.Bind("COMPILE_DEFINITIONS"_s, TryCompileCompileDefs,
@@ -170,6 +170,13 @@ auto const TryCompileBaseNonProjectArgParser =
.BIND_LANG_PROPS(OBJCXX)
/* keep semicolon on own line */;
+auto const TryCompileBaseNewSourcesArgParser =
+ cmArgumentParser<Arguments>{ TryCompileBaseSourcesArgParser }
+ .Bind("SOURCE_FROM_ARG"_s, &Arguments::SourceFromArg)
+ .Bind("SOURCE_FROM_VAR"_s, &Arguments::SourceFromVar)
+ .Bind("SOURCE_FROM_FILE"_s, &Arguments::SourceFromFile)
+ /* keep semicolon on own line */;
+
auto const TryCompileBaseProjectArgParser =
cmArgumentParser<Arguments>{ TryCompileBaseArgParser }
.Bind("PROJECT"_s, &Arguments::ProjectName)
@@ -182,10 +189,10 @@ auto const TryCompileProjectArgParser =
makeTryCompileParser(TryCompileBaseProjectArgParser);
auto const TryCompileSourcesArgParser =
- makeTryCompileParser(TryCompileBaseNonProjectArgParser);
+ makeTryCompileParser(TryCompileBaseNewSourcesArgParser);
auto const TryCompileOldArgParser =
- makeTryCompileParser(TryCompileBaseNonProjectArgParser)
+ makeTryCompileParser(TryCompileBaseSourcesArgParser)
.Bind(1, &Arguments::BinaryDirectory)
.Bind(2, &Arguments::SourceDirectoryOrFile)
.Bind(3, &Arguments::ProjectName)
@@ -193,7 +200,7 @@ auto const TryCompileOldArgParser =
/* keep semicolon on own line */;
auto const TryRunSourcesArgParser =
- makeTryRunParser(TryCompileBaseNonProjectArgParser);
+ makeTryRunParser(TryCompileBaseNewSourcesArgParser);
auto const TryRunOldArgParser = makeTryRunParser(TryCompileOldArgParser);
@@ -393,8 +400,27 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
return false;
}
- // only valid for srcfile signatures
- if (!this->SrcFileSignature) {
+ if (this->SrcFileSignature) {
+ if (arguments.SourceFromArg && arguments.SourceFromArg->size() % 2) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "SOURCE_FROM_ARG requires exactly two arguments");
+ return false;
+ }
+ if (arguments.SourceFromVar && arguments.SourceFromVar->size() % 2) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "SOURCE_FROM_VAR requires exactly two arguments");
+ return false;
+ }
+ if (arguments.SourceFromFile && arguments.SourceFromFile->size() % 2) {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "SOURCE_FROM_FILE requires exactly two arguments");
+ return false;
+ }
+ } else {
+ // only valid for srcfile signatures
if (!arguments.LangProps.empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
@@ -415,6 +441,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
return false;
}
}
+
// make sure the binary directory exists
if (useUniqueBinaryDirectory) {
this->BinaryDirectory =
@@ -445,10 +472,60 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
std::vector<std::string> sources;
if (arguments.Sources) {
sources = std::move(*arguments.Sources);
- } else {
- // TODO: ensure SourceDirectoryOrFile has a value
+ } else if (arguments.SourceDirectoryOrFile) {
sources.emplace_back(*arguments.SourceDirectoryOrFile);
}
+ if (arguments.SourceFromArg) {
+ auto const k = arguments.SourceFromArg->size();
+ for (auto i = decltype(k){ 0 }; i < k; i += 2) {
+ const auto& name = (*arguments.SourceFromArg)[i + 0];
+ const auto& content = (*arguments.SourceFromArg)[i + 1];
+ auto out = this->WriteSource(name, content, "SOURCES_FROM_ARG");
+ if (out.empty()) {
+ return false;
+ }
+ sources.emplace_back(std::move(out));
+ }
+ }
+ if (arguments.SourceFromVar) {
+ auto const k = arguments.SourceFromVar->size();
+ for (auto i = decltype(k){ 0 }; i < k; i += 2) {
+ const auto& name = (*arguments.SourceFromVar)[i + 0];
+ const auto& var = (*arguments.SourceFromVar)[i + 1];
+ const auto& content = this->Makefile->GetDefinition(var);
+ auto out = this->WriteSource(name, content, "SOURCES_FROM_VAR");
+ if (out.empty()) {
+ return false;
+ }
+ sources.emplace_back(std::move(out));
+ }
+ }
+ if (arguments.SourceFromFile) {
+ auto const k = arguments.SourceFromFile->size();
+ for (auto i = decltype(k){ 0 }; i < k; i += 2) {
+ const auto& dst = (*arguments.SourceFromFile)[i + 0];
+ const auto& src = (*arguments.SourceFromFile)[i + 1];
+
+ if (!cmSystemTools::GetFilenamePath(dst).empty()) {
+ const auto& msg =
+ cmStrCat("SOURCE_FROM_FILE given invalid filename \"", dst, "\"");
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+
+ auto dstPath = cmStrCat(this->BinaryDirectory, "/", dst);
+ auto const result = cmSystemTools::CopyFileAlways(src, dstPath);
+ if (!result.IsSuccess()) {
+ const auto& msg = cmStrCat("SOURCE_FROM_FILE failed to copy \"", src,
+ "\": ", result.GetString());
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return false;
+ }
+
+ sources.emplace_back(std::move(dstPath));
+ }
+ }
+ // TODO: ensure sources is not empty
// Detect languages to enable.
cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
@@ -1128,3 +1205,34 @@ void cmCoreTryCompile::FindOutputFile(const std::string& targetName)
this->OutputFile = cmSystemTools::CollapseFullPath(outputFileLocation);
}
+
+std::string cmCoreTryCompile::WriteSource(std::string const& filename,
+ std::string const& content,
+ char const* command) const
+{
+ if (!cmSystemTools::GetFilenamePath(filename).empty()) {
+ const auto& msg =
+ cmStrCat(command, " given invalid filename \"", filename, "\"");
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return {};
+ }
+
+ auto filepath = cmStrCat(this->BinaryDirectory, "/", filename);
+ cmsys::ofstream file{ filepath.c_str(), std::ios::out };
+ if (!file) {
+ const auto& msg =
+ cmStrCat(command, " failed to open \"", filename, "\" for writing");
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return {};
+ }
+
+ file << content;
+ if (!file) {
+ const auto& msg = cmStrCat(command, " failed to write \"", filename, "\"");
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
+ return {};
+ }
+
+ file.close();
+ return filepath;
+}