summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2020-10-16 16:25:19 (GMT)
committerBrad King <brad.king@kitware.com>2020-12-11 13:24:06 (GMT)
commitf36af9228b2ad36442f0cce9e8c8533fadef65aa (patch)
treeea255852e33dd71642d8e0e8ba913ff1764511de
parentc887cefd9a12342a3ac8dc5c1dbb692b7e8d27af (diff)
downloadCMake-f36af9228b2ad36442f0cce9e8c8533fadef65aa.zip
CMake-f36af9228b2ad36442f0cce9e8c8533fadef65aa.tar.gz
CMake-f36af9228b2ad36442f0cce9e8c8533fadef65aa.tar.bz2
cmLocalGenerator: Evaluate generator expressions in custom command outputs
Custom commands with generator expressions in their OUTPUTs or BYPRODUCTS are still attached to a single `.rule` file. We use an internal map to look up the source file holding the custom command for a given output. Populate this map using the outputs and byproducts from all configurations after evaluating the generator expressions for each configuration. Issue: #12877
-rw-r--r--Source/cmLocalGenerator.cxx103
-rw-r--r--Source/cmLocalGenerator.h2
2 files changed, 101 insertions, 4 deletions
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index a8c9b77..dd1779b 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -20,6 +20,7 @@
#include "cmsys/RegularExpression.hxx"
+#include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
@@ -3832,6 +3833,43 @@ void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output,
}
}
+std::string ComputeCustomCommandRuleFileName(cmLocalGenerator& lg,
+ cmListFileBacktrace const& bt,
+ std::string const& output)
+{
+ // If the output path has no generator expressions, use it directly.
+ if (cmGeneratorExpression::Find(output) == std::string::npos) {
+ return output;
+ }
+
+ // The output path contains a generator expression, but we must choose
+ // a single source file path to which to attach the custom command.
+ // Use some heuristics to provie a nice-looking name when possible.
+
+ // If the only genex is $<CONFIG>, replace that gracefully.
+ {
+ std::string simple = output;
+ cmSystemTools::ReplaceString(simple, "$<CONFIG>", "(CONFIG)");
+ if (cmGeneratorExpression::Find(simple) == std::string::npos) {
+ return simple;
+ }
+ }
+
+ // If the genex evaluates to the same value in all configurations, use that.
+ {
+ std::vector<std::string> allConfigOutputs =
+ lg.ExpandCustomCommandOutputGenex(output, bt);
+ if (allConfigOutputs.size() == 1) {
+ return allConfigOutputs.front();
+ }
+ }
+
+ // Fall back to a deterministic unique name.
+ cmCryptoHash h(cmCryptoHash::AlgoSHA256);
+ return cmStrCat(lg.GetCurrentBinaryDirectory(), "/CMakeFiles/",
+ h.HashString(output).substr(0, 16));
+}
+
cmSourceFile* AddCustomCommand(
cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
cmCommandOrigin origin, const std::vector<std::string>& outputs,
@@ -3871,7 +3909,8 @@ cmSourceFile* AddCustomCommand(
cmGlobalGenerator* gg = lg.GetGlobalGenerator();
// Construct a rule file associated with the first output produced.
- std::string outName = gg->GenerateRuleFile(outputs[0]);
+ std::string outName = gg->GenerateRuleFile(
+ ComputeCustomCommandRuleFileName(lg, lfbt, outputs[0]));
// Check if the rule file already exists.
file = mf->GetSource(outName, cmSourceFileLocationKind::Known);
@@ -4012,7 +4051,22 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
const cmCustomCommandLines& commandLines)
{
// Lookup an existing command.
- if (cmSourceFile* sf = lg.GetSourceFileWithOutput(output)) {
+ cmSourceFile* sf = nullptr;
+ if (cmGeneratorExpression::Find(output) == std::string::npos) {
+ sf = lg.GetSourceFileWithOutput(output);
+ } else {
+ // This output path has a generator expression. Evaluate it to
+ // find the output for any configurations.
+ for (std::string const& out :
+ lg.ExpandCustomCommandOutputGenex(output, lfbt)) {
+ sf = lg.GetSourceFileWithOutput(out);
+ if (sf) {
+ break;
+ }
+ }
+ }
+
+ if (sf) {
if (cmCustomCommand* cc = sf->GetCustomCommand()) {
cc->AppendCommands(commandLines);
cc->AppendDepends(depends);
@@ -4160,12 +4214,42 @@ std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths(
return paths;
}
+std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex(
+ std::string const& o, cmListFileBacktrace const& bt)
+{
+ std::vector<std::string> allConfigOutputs;
+ cmGeneratorExpression ge(bt);
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(o);
+ std::vector<std::string> configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ for (std::string const& config : configs) {
+ std::vector<std::string> configOutputs =
+ this->ExpandCustomCommandOutputPaths(*cge, config);
+ allConfigOutputs.reserve(allConfigOutputs.size() + configOutputs.size());
+ std::move(configOutputs.begin(), configOutputs.end(),
+ std::back_inserter(allConfigOutputs));
+ }
+ auto endUnique =
+ cmRemoveDuplicates(allConfigOutputs.begin(), allConfigOutputs.end());
+ allConfigOutputs.erase(endUnique, allConfigOutputs.end());
+ return allConfigOutputs;
+}
+
void cmLocalGenerator::AddTargetByproducts(
cmTarget* target, const std::vector<std::string>& byproducts,
cmListFileBacktrace const& bt, cmCommandOrigin origin)
{
for (std::string const& o : byproducts) {
- this->UpdateOutputToSourceMap(o, target, bt, origin);
+ if (cmGeneratorExpression::Find(o) == std::string::npos) {
+ this->UpdateOutputToSourceMap(o, target, bt, origin);
+ continue;
+ }
+
+ // This byproduct path has a generator expression. Evaluate it to
+ // register the byproducts for all configurations.
+ for (std::string const& b : this->ExpandCustomCommandOutputGenex(o, bt)) {
+ this->UpdateOutputToSourceMap(b, target, bt, cmCommandOrigin::Generator);
+ }
}
}
@@ -4174,7 +4258,18 @@ void cmLocalGenerator::AddSourceOutputs(
OutputRole role, cmListFileBacktrace const& bt, cmCommandOrigin origin)
{
for (std::string const& o : outputs) {
- this->UpdateOutputToSourceMap(o, source, role, bt, origin);
+ if (cmGeneratorExpression::Find(o) == std::string::npos) {
+ this->UpdateOutputToSourceMap(o, source, role, bt, origin);
+ continue;
+ }
+
+ // This output path has a generator expression. Evaluate it to
+ // register the outputs for all configurations.
+ for (std::string const& out :
+ this->ExpandCustomCommandOutputGenex(o, bt)) {
+ this->UpdateOutputToSourceMap(out, source, role, bt,
+ cmCommandOrigin::Generator);
+ }
}
}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 79ffcfb..581badb 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -365,6 +365,8 @@ public:
std::vector<std::string> ExpandCustomCommandOutputPaths(
cmCompiledGeneratorExpression const& cge, std::string const& config);
+ std::vector<std::string> ExpandCustomCommandOutputGenex(
+ std::string const& o, cmListFileBacktrace const& bt);
/**
* Add target byproducts.