diff options
author | Daniel Eiband <daniel.eiband@brainlab.com> | 2019-09-11 10:19:43 (GMT) |
---|---|---|
committer | Daniel Eiband <daniel.eiband@brainlab.com> | 2019-09-12 14:01:45 (GMT) |
commit | 2edb0b71edd36031f2fcc0b65633c1c16f8e9268 (patch) | |
tree | 128bf8bda1b93f3b6d7731a8869cf1a50b5e17ff /Source/cmMakefile.cxx | |
parent | 62d59323899330197e795872c13c1d300a97d088 (diff) | |
download | CMake-2edb0b71edd36031f2fcc0b65633c1c16f8e9268.zip CMake-2edb0b71edd36031f2fcc0b65633c1c16f8e9268.tar.gz CMake-2edb0b71edd36031f2fcc0b65633c1c16f8e9268.tar.bz2 |
cmMakefile: Add lookup from source name to targets via byproducts
Given an output source name it is now possible to query which target has a
byproduct of this name or has a PRE_BUILD, PRE_LINK, or POST_BUILD build event
with a byproduct of this name.
In a call to GetSourceFileWithOutput a matching byproduct can now optionally be
returned as fallback if there is no matching output of a custom command.
Default behavior is not changed by this commit.
Diffstat (limited to 'Source/cmMakefile.cxx')
-rw-r--r-- | Source/cmMakefile.cxx | 160 |
1 files changed, 136 insertions, 24 deletions
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 3a80b02..9e64f97 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -908,6 +908,37 @@ 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( @@ -1003,35 +1034,47 @@ cmSourceFile* cmMakefile::AddCustomCommandToOutput( 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( @@ -1194,6 +1237,8 @@ cmTarget* cmMakefile::AddUtilityCommand( } else { cmSystemTools::Error("Could not get source file entry for " + force); } + + this->UpdateOutputToSourceMap(byproducts, target); } return target; } @@ -2007,6 +2052,7 @@ 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; @@ -2026,11 +2072,45 @@ bool AnyOutputMatches(const std::string& name, } 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 { + // 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. for (cmSourceFile* src : this->SourceFiles) { @@ -2041,25 +2121,57 @@ cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput( // 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; } |