summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorMatthew Woehlke <matthew.woehlke@kitware.com>2022-09-21 17:34:02 (GMT)
committerMatthew Woehlke <matthew.woehlke@kitware.com>2022-09-22 17:33:27 (GMT)
commitcb14ae2b870e9568d18990992882e0facacf22d4 (patch)
treeb7c203b809fe854610a36b0d97b6299b9d9e18cc /Source
parent620cf9efa78c8862558ac321c043194d1cb6eb19 (diff)
downloadCMake-cb14ae2b870e9568d18990992882e0facacf22d4.zip
CMake-cb14ae2b870e9568d18990992882e0facacf22d4.tar.gz
CMake-cb14ae2b870e9568d18990992882e0facacf22d4.tar.bz2
try_compile: Add SOURCE_FROM_{ARG,VAR}
Add ability to "feed" try_compile (and try_run) sources more directly, either from literal content, or from a CMake variable which contains literal content. This saves the user from needing a separate step to write the content to a file, and allows for the sources to only exist in the scratch directory.
Diffstat (limited to 'Source')
-rw-r--r--Source/cmCoreTryCompile.cxx92
-rw-r--r--Source/cmCoreTryCompile.h7
2 files changed, 91 insertions, 8 deletions
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 2f63b3c..0ef32c0 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,12 @@ 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)
+ /* keep semicolon on own line */;
+
auto const TryCompileBaseProjectArgParser =
cmArgumentParser<Arguments>{ TryCompileBaseArgParser }
.Bind("PROJECT"_s, &Arguments::ProjectName)
@@ -182,10 +188,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)
@@ -196,7 +202,7 @@ auto const TryRunProjectArgParser =
makeTryRunParser(TryCompileBaseProjectArgParser);
auto const TryRunSourcesArgParser =
- makeTryRunParser(TryCompileBaseNonProjectArgParser);
+ makeTryRunParser(TryCompileBaseNewSourcesArgParser);
auto const TryRunOldArgParser = makeTryRunParser(TryCompileOldArgParser);
@@ -397,8 +403,21 @@ 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;
+ }
+ } else {
+ // only valid for srcfile signatures
if (!arguments.LangProps.empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
@@ -419,6 +438,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
return false;
}
}
+
// make sure the binary directory exists
if (useUniqueBinaryDirectory) {
this->BinaryDirectory =
@@ -449,10 +469,35 @@ 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));
+ }
+ }
+ // TODO: ensure sources is not empty
// Detect languages to enable.
cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
@@ -1132,3 +1177,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;
+}
diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h
index 729aa9f..75dcf6e 100644
--- a/Source/cmCoreTryCompile.h
+++ b/Source/cmCoreTryCompile.h
@@ -40,6 +40,10 @@ public:
cm::optional<std::string> ProjectName;
cm::optional<std::string> TargetName;
cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> Sources;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ SourceFromArg;
+ cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>>
+ SourceFromVar;
ArgumentParser::MaybeEmpty<std::vector<std::string>> CMakeFlags{
1, "CMAKE_FLAGS"
}; // fake argv[0]
@@ -103,6 +107,9 @@ public:
cmMakefile* Makefile;
private:
+ std::string WriteSource(std::string const& name, std::string const& content,
+ char const* command) const;
+
Arguments ParseArgs(
const cmRange<std::vector<std::string>::const_iterator>& args,
const cmArgumentParser<Arguments>& parser,