summaryrefslogtreecommitdiffstats
path: root/Source/cmMakefile.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmMakefile.cxx')
-rw-r--r--Source/cmMakefile.cxx226
1 files changed, 183 insertions, 43 deletions
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index d73a285..88d03f9 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -908,12 +908,44 @@ void cmMakefile::AddCustomCommandToTarget(
t.AddPostBuildCommand(cc);
break;
}
+ this->UpdateOutputToSourceMap(byproducts, &t);
+}
+
+void cmMakefile::UpdateOutputToSourceMap(
+ std::vector<std::string> const& byproducts, cmTarget* target)
+{
+ for (std::string const& o : byproducts) {
+ this->UpdateOutputToSourceMap(o, target);
+ }
+}
+
+void cmMakefile::UpdateOutputToSourceMap(std::string const& byproduct,
+ cmTarget* target)
+{
+ SourceEntry entry;
+ entry.Sources.Target = target;
+
+ auto pr = this->OutputToSource.emplace(byproduct, entry);
+ if (!pr.second) {
+ SourceEntry& current = pr.first->second;
+ // Has the target already been set?
+ if (!current.Sources.Target) {
+ current.Sources.Target = target;
+ } else {
+ // Multiple custom commands/targets produce the same output (source file
+ // or target). See also comment in other UpdateOutputToSourceMap
+ // overload.
+ //
+ // TODO: Warn the user about this case.
+ }
+ }
}
cmSourceFile* cmMakefile::AddCustomCommandToOutput(
const std::vector<std::string>& outputs,
const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends, const std::string& main_dependency,
+ const cmImplicitDependsList& implicit_depends,
const cmCustomCommandLines& commandLines, const char* comment,
const char* workingDir, bool replace, bool escapeOldStyle,
bool uses_terminal, bool command_expand_lists, const std::string& depfile,
@@ -998,40 +1030,53 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
this, outputs, byproducts, depends2, commandLines, comment, workingDir);
cc->SetEscapeOldStyle(escapeOldStyle);
cc->SetEscapeAllowMakeVars(true);
+ cc->SetImplicitDepends(implicit_depends);
cc->SetUsesTerminal(uses_terminal);
cc->SetCommandExpandLists(command_expand_lists);
cc->SetDepfile(depfile);
cc->SetJobPool(job_pool);
file->SetCustomCommand(cc);
- this->UpdateOutputToSourceMap(outputs, file);
+ this->UpdateOutputToSourceMap(outputs, file, false);
+ this->UpdateOutputToSourceMap(byproducts, file, true);
}
return file;
}
void cmMakefile::UpdateOutputToSourceMap(
- std::vector<std::string> const& outputs, cmSourceFile* source)
+ std::vector<std::string> const& outputs, cmSourceFile* source,
+ bool byproduct)
{
for (std::string const& o : outputs) {
- this->UpdateOutputToSourceMap(o, source);
+ this->UpdateOutputToSourceMap(o, source, byproduct);
}
}
void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
- cmSourceFile* source)
-{
- auto i = this->OutputToSource.find(output);
- if (i != this->OutputToSource.end()) {
- // Multiple custom commands produce the same output but may
- // be attached to a different source file (MAIN_DEPENDENCY).
- // LinearGetSourceFileWithOutput would return the first one,
- // so keep the mapping for the first one.
- //
- // TODO: Warn the user about this case. However, the VS 8 generator
- // triggers it for separate generate.stamp rules in ZERO_CHECK and
- // individual targets.
- return;
+ cmSourceFile* source, bool byproduct)
+{
+ SourceEntry entry;
+ entry.Sources.Source = source;
+ entry.Sources.SourceIsByproduct = byproduct;
+
+ auto pr = this->OutputToSource.emplace(output, entry);
+ if (!pr.second) {
+ SourceEntry& current = pr.first->second;
+ // Outputs take precedence over byproducts
+ if (!current.Sources.Source ||
+ (current.Sources.SourceIsByproduct && !byproduct)) {
+ current.Sources.Source = source;
+ current.Sources.SourceIsByproduct = false;
+ } else {
+ // Multiple custom commands produce the same output but may
+ // be attached to a different source file (MAIN_DEPENDENCY).
+ // LinearGetSourceFileWithOutput would return the first one,
+ // so keep the mapping for the first one.
+ //
+ // TODO: Warn the user about this case. However, the VS 8 generator
+ // triggers it for separate generate.stamp rules in ZERO_CHECK and
+ // individual targets.
+ }
}
- this->OutputToSource[output] = source;
}
cmSourceFile* cmMakefile::AddCustomCommandToOutput(
@@ -1044,10 +1089,11 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput(
std::vector<std::string> outputs;
outputs.push_back(output);
std::vector<std::string> no_byproducts;
+ cmImplicitDependsList no_implicit_depends;
return this->AddCustomCommandToOutput(
- outputs, no_byproducts, depends, main_dependency, commandLines, comment,
- workingDir, replace, escapeOldStyle, uses_terminal, command_expand_lists,
- depfile, job_pool);
+ outputs, no_byproducts, depends, main_dependency, no_implicit_depends,
+ commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
+ command_expand_lists, depfile, job_pool);
}
void cmMakefile::AddCustomCommandOldStyle(
@@ -1108,6 +1154,23 @@ void cmMakefile::AddCustomCommandOldStyle(
}
}
+bool cmMakefile::AppendCustomCommandToOutput(
+ const std::string& output, const std::vector<std::string>& depends,
+ const cmImplicitDependsList& implicit_depends,
+ const cmCustomCommandLines& commandLines)
+{
+ // Lookup an existing command.
+ if (cmSourceFile* sf = this->GetSourceFileWithOutput(output)) {
+ if (cmCustomCommand* cc = sf->GetCustomCommand()) {
+ cc->AppendCommands(commandLines);
+ cc->AppendDepends(depends);
+ cc->AppendImplicitDepends(implicit_depends);
+ return true;
+ }
+ }
+ return false;
+}
+
cmTarget* cmMakefile::AddUtilityCommand(
const std::string& utilityName, TargetOrigin origin, bool excludeFromAll,
const std::vector<std::string>& depends, const char* workingDirectory,
@@ -1181,11 +1244,12 @@ cmTarget* cmMakefile::AddUtilityCommand(
std::vector<std::string> forced;
forced.push_back(force);
std::string no_main_dependency;
+ cmImplicitDependsList no_implicit_depends;
bool no_replace = false;
this->AddCustomCommandToOutput(
- forced, byproducts, depends, no_main_dependency, commandLines, comment,
- workingDirectory, no_replace, escapeOldStyle, uses_terminal,
- command_expand_lists, /*depfile=*/"", job_pool);
+ forced, byproducts, depends, no_main_dependency, no_implicit_depends,
+ commandLines, comment, workingDirectory, no_replace, escapeOldStyle,
+ uses_terminal, command_expand_lists, /*depfile=*/"", job_pool);
cmSourceFile* sf = target->AddSourceCMP0049(force);
// The output is not actually created so mark it symbolic.
@@ -1194,6 +1258,8 @@ cmTarget* cmMakefile::AddUtilityCommand(
} else {
cmSystemTools::Error("Could not get source file entry for " + force);
}
+
+ this->UpdateOutputToSourceMap(byproducts, target);
}
return target;
}
@@ -2007,52 +2073,126 @@ cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
this->Targets
.emplace(name, cmTarget(name, type, cmTarget::VisibilityNormal, this))
.first;
+ this->OrderedTargets.push_back(&it->second);
this->GetGlobalGenerator()->IndexTarget(&it->second);
this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
return &it->second;
}
+namespace {
+bool AnyOutputMatches(const std::string& name,
+ const std::vector<std::string>& outputs)
+{
+ for (std::string const& output : outputs) {
+ std::string::size_type pos = output.rfind(name);
+ // If the output matches exactly
+ if (pos != std::string::npos && pos == output.size() - name.size() &&
+ (pos == 0 || output[pos - 1] == '/')) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AnyTargetCommandOutputMatches(
+ const std::string& name, const std::vector<cmCustomCommand>& commands)
+{
+ for (cmCustomCommand const& command : commands) {
+ if (AnyOutputMatches(name, command.GetByproducts())) {
+ return true;
+ }
+ }
+ return false;
+}
+}
+
+cmTarget* cmMakefile::LinearGetTargetWithOutput(const std::string& name) const
+{
+ // We go through the ordered vector of targets to get reproducible results
+ // should multiple names match.
+ for (cmTarget* t : this->OrderedTargets) {
+ // Does the output of any command match the source file name?
+ if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
+ return t;
+ }
+ if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
+ return t;
+ }
+ if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
+ return t;
+ }
+ }
+ return nullptr;
+}
+
cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput(
- const std::string& name) const
+ const std::string& name, cmSourceOutputKind kind, bool& byproduct) const
{
- std::string out;
+ // Outputs take precedence over byproducts.
+ byproduct = false;
+ cmSourceFile* fallback = nullptr;
- // look through all the source files that have custom commands
- // and see if the custom command has the passed source file as an output
+ // Look through all the source files that have custom commands and see if the
+ // custom command has the passed source file as an output.
for (cmSourceFile* src : this->SourceFiles) {
- // does this source file have a custom command?
+ // Does this source file have a custom command?
if (src->GetCustomCommand()) {
// Does the output of the custom command match the source file name?
- const std::vector<std::string>& outputs =
- src->GetCustomCommand()->GetOutputs();
- for (std::string const& output : outputs) {
- out = output;
- std::string::size_type pos = out.rfind(name);
- // If the output matches exactly
- if (pos != std::string::npos && pos == out.size() - name.size() &&
- (pos == 0 || out[pos - 1] == '/')) {
- return src;
+ if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
+ // Return the first matching output.
+ return src;
+ }
+ if (kind == cmSourceOutputKind::OutputOrByproduct) {
+ if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
+ // Do not return the source yet as there might be a matching output.
+ fallback = src;
}
}
}
}
- // otherwise return NULL
- return nullptr;
+ // Did we find a byproduct?
+ byproduct = fallback != nullptr;
+ return fallback;
}
-cmSourceFile* cmMakefile::GetSourceFileWithOutput(
+cmSourcesWithOutput cmMakefile::GetSourcesWithOutput(
const std::string& name) const
{
+ // Linear search? Also see GetSourceFileWithOutput for detail.
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ cmSourcesWithOutput sources;
+ sources.Target = this->LinearGetTargetWithOutput(name);
+ sources.Source = this->LinearGetSourceFileWithOutput(
+ name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
+ return sources;
+ }
+ // Otherwise we use an efficient lookup map.
+ auto o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end()) {
+ return o->second.Sources;
+ }
+ return {};
+}
+
+cmSourceFile* cmMakefile::GetSourceFileWithOutput(
+ const std::string& name, cmSourceOutputKind kind) const
+{
// If the queried path is not absolute we use the backward compatible
// linear-time search for an output with a matching suffix.
if (!cmSystemTools::FileIsFullPath(name)) {
- return this->LinearGetSourceFileWithOutput(name);
+ bool byproduct = false;
+ return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
}
// Otherwise we use an efficient lookup map.
auto o = this->OutputToSource.find(name);
- if (o != this->OutputToSource.end()) {
- return (*o).second;
+ if (o != this->OutputToSource.end() &&
+ (!o->second.Sources.SourceIsByproduct ||
+ kind == cmSourceOutputKind::OutputOrByproduct)) {
+ // Source file could also be null pointer for example if we found the
+ // byproduct of a utility target or a PRE_BUILD, PRE_LINK, or POST_BUILD
+ // command of a target.
+ return o->second.Sources.Source;
}
return nullptr;
}