cmLocalGenerator: Migrate custom command output lookup from cmMakefile
Since commit 777ceaea94
(cmMakefile: Delay custom command creation,
2019-10-17, v3.17.0-rc1~352^2) we process custom command declarations at
generate time. Therefore we do not need to look up what source file
holds the custom command producing a given output until generate time.
This commit is contained in:
parent
26464da5d3
commit
0090a11a42
@ -2986,7 +2986,8 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
|
|||||||
auto i = this->NameMap.lower_bound(name);
|
auto i = this->NameMap.lower_bound(name);
|
||||||
if (i == this->NameMap.end() || i->first != name) {
|
if (i == this->NameMap.end() || i->first != name) {
|
||||||
// Check if we know how to generate this file.
|
// Check if we know how to generate this file.
|
||||||
cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name);
|
cmSourcesWithOutput sources =
|
||||||
|
this->LocalGenerator->GetSourcesWithOutput(name);
|
||||||
// If we failed to find a target or source and we have a relative path, it
|
// If we failed to find a target or source and we have a relative path, it
|
||||||
// might be a valid source if made relative to the current binary
|
// might be a valid source if made relative to the current binary
|
||||||
// directory.
|
// directory.
|
||||||
@ -2996,7 +2997,7 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
|
|||||||
cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
|
cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
|
||||||
fullname = cmSystemTools::CollapseFullPath(
|
fullname = cmSystemTools::CollapseFullPath(
|
||||||
fullname, this->Makefile->GetHomeOutputDirectory());
|
fullname, this->Makefile->GetHomeOutputDirectory());
|
||||||
sources = this->Makefile->GetSourcesWithOutput(fullname);
|
sources = this->LocalGenerator->GetSourcesWithOutput(fullname);
|
||||||
}
|
}
|
||||||
i = this->NameMap.emplace_hint(i, name, sources);
|
i = this->NameMap.emplace_hint(i, name, sources);
|
||||||
}
|
}
|
||||||
|
@ -763,9 +763,9 @@ bool cmGhsMultiTargetGenerator::VisitCustomCommand(
|
|||||||
/* set temporary mark; check if revisit*/
|
/* set temporary mark; check if revisit*/
|
||||||
if (temp.insert(si).second) {
|
if (temp.insert(si).second) {
|
||||||
for (auto& di : si->GetCustomCommand()->GetDepends()) {
|
for (auto& di : si->GetCustomCommand()->GetDepends()) {
|
||||||
cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator()
|
cmSourceFile const* sf =
|
||||||
->GetMakefile()
|
this->GeneratorTarget->GetLocalGenerator()->GetSourceFileWithOutput(
|
||||||
->GetSourceFileWithOutput(di);
|
di);
|
||||||
/* if sf exists then visit */
|
/* if sf exists then visit */
|
||||||
if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
|
if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -3918,10 +3918,35 @@ cmSourceFile* AddCustomCommand(
|
|||||||
cc->SetJobPool(job_pool);
|
cc->SetJobPool(job_pool);
|
||||||
file->SetCustomCommand(std::move(cc));
|
file->SetCustomCommand(std::move(cc));
|
||||||
|
|
||||||
mf->AddSourceOutputs(file, outputs, byproducts);
|
lg.AddSourceOutputs(file, outputs, byproducts);
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -3937,8 +3962,6 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
|
|||||||
const std::string& job_pool,
|
const std::string& job_pool,
|
||||||
bool command_expand_lists, bool stdPipesUTF8)
|
bool command_expand_lists, bool stdPipesUTF8)
|
||||||
{
|
{
|
||||||
cmMakefile* mf = lg.GetMakefile();
|
|
||||||
|
|
||||||
// Always create the byproduct sources and mark them generated.
|
// Always create the byproduct sources and mark them generated.
|
||||||
CreateGeneratedSources(lg, byproducts, origin, lfbt);
|
CreateGeneratedSources(lg, byproducts, origin, lfbt);
|
||||||
|
|
||||||
@ -3964,7 +3987,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mf->AddTargetByproducts(target, byproducts);
|
lg.AddTargetByproducts(target, byproducts);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmSourceFile* AddCustomCommandToOutput(
|
cmSourceFile* AddCustomCommandToOutput(
|
||||||
@ -3996,7 +4019,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
|
|||||||
const cmCustomCommandLines& commandLines)
|
const cmCustomCommandLines& commandLines)
|
||||||
{
|
{
|
||||||
// Lookup an existing command.
|
// Lookup an existing command.
|
||||||
if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) {
|
if (cmSourceFile* sf = lg.GetSourceFileWithOutput(output)) {
|
||||||
if (cmCustomCommand* cc = sf->GetCustomCommand()) {
|
if (cmCustomCommand* cc = sf->GetCustomCommand()) {
|
||||||
cc->AppendCommands(commandLines);
|
cc->AppendCommands(commandLines);
|
||||||
cc->AppendDepends(depends);
|
cc->AppendDepends(depends);
|
||||||
@ -4040,7 +4063,7 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
|
|||||||
/*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists,
|
/*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists,
|
||||||
/*depfile=*/"", job_pool, stdPipesUTF8);
|
/*depfile=*/"", job_pool, stdPipesUTF8);
|
||||||
if (rule) {
|
if (rule) {
|
||||||
lg.GetMakefile()->AddTargetByproducts(target, byproducts);
|
lg.AddTargetByproducts(target, byproducts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!force.NameCMP0049.empty()) {
|
if (!force.NameCMP0049.empty()) {
|
||||||
@ -4088,3 +4111,166 @@ std::vector<std::string> ComputeISPCExtraObjects(
|
|||||||
return computedObjects;
|
return computedObjects;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmSourcesWithOutput cmLocalGenerator::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* cmLocalGenerator::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)) {
|
||||||
|
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() &&
|
||||||
|
(!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, a PRE_BUILD, PRE_LINK, or POST_BUILD
|
||||||
|
// command of a target, or a not yet created custom command.
|
||||||
|
return o->second.Sources.Source;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmLocalGenerator::AddTargetByproducts(
|
||||||
|
cmTarget* target, const std::vector<std::string>& byproducts)
|
||||||
|
{
|
||||||
|
for (std::string const& o : byproducts) {
|
||||||
|
this->UpdateOutputToSourceMap(o, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmLocalGenerator::AddSourceOutputs(
|
||||||
|
cmSourceFile* source, const std::vector<std::string>& outputs,
|
||||||
|
const std::vector<std::string>& byproducts)
|
||||||
|
{
|
||||||
|
for (std::string const& o : outputs) {
|
||||||
|
this->UpdateOutputToSourceMap(o, source, false);
|
||||||
|
}
|
||||||
|
for (std::string const& o : byproducts) {
|
||||||
|
this->UpdateOutputToSourceMap(o, source, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmLocalGenerator::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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output,
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmTarget* cmLocalGenerator::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->Makefile->GetOrderedTargets()) {
|
||||||
|
// 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* cmLocalGenerator::LinearGetSourceFileWithOutput(
|
||||||
|
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 (const auto& src : this->Makefile->GetSourceFiles()) {
|
||||||
|
// Does this source file have a custom command?
|
||||||
|
if (src->GetCustomCommand()) {
|
||||||
|
// Does the output of the custom command match the source file name?
|
||||||
|
if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
|
||||||
|
// Return the first matching output.
|
||||||
|
return src.get();
|
||||||
|
}
|
||||||
|
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.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Did we find a byproduct?
|
||||||
|
byproduct = fallback != nullptr;
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
@ -36,6 +36,24 @@ class cmState;
|
|||||||
class cmTarget;
|
class cmTarget;
|
||||||
class cmake;
|
class cmake;
|
||||||
|
|
||||||
|
/** Flag if byproducts shall also be considered. */
|
||||||
|
enum class cmSourceOutputKind
|
||||||
|
{
|
||||||
|
OutputOnly,
|
||||||
|
OutputOrByproduct
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Target and source file which have a specific output. */
|
||||||
|
struct cmSourcesWithOutput
|
||||||
|
{
|
||||||
|
/** Target with byproduct. */
|
||||||
|
cmTarget* Target = nullptr;
|
||||||
|
|
||||||
|
/** Source file with output or byproduct. */
|
||||||
|
cmSourceFile* Source = nullptr;
|
||||||
|
bool SourceIsByproduct = false;
|
||||||
|
};
|
||||||
|
|
||||||
/** \class cmLocalGenerator
|
/** \class cmLocalGenerator
|
||||||
* \brief Create required build files for a directory.
|
* \brief Create required build files for a directory.
|
||||||
*
|
*
|
||||||
@ -337,6 +355,34 @@ public:
|
|||||||
bool command_expand_lists = false, const std::string& job_pool = "",
|
bool command_expand_lists = false, const std::string& job_pool = "",
|
||||||
bool stdPipesUTF8 = false);
|
bool stdPipesUTF8 = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add target byproducts.
|
||||||
|
*/
|
||||||
|
void AddTargetByproducts(cmTarget* target,
|
||||||
|
const std::vector<std::string>& byproducts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add source file outputs.
|
||||||
|
*/
|
||||||
|
void AddSourceOutputs(cmSourceFile* source,
|
||||||
|
const std::vector<std::string>& outputs,
|
||||||
|
const std::vector<std::string>& byproducts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the target if the provided source name is a byproduct of a utility
|
||||||
|
* target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
|
||||||
|
* Return the source file which has the provided source name as output.
|
||||||
|
*/
|
||||||
|
cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a source file that has the provided source name as an output?
|
||||||
|
* If so then return it.
|
||||||
|
*/
|
||||||
|
cmSourceFile* GetSourceFileWithOutput(
|
||||||
|
const std::string& name,
|
||||||
|
cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
|
||||||
|
|
||||||
std::string GetProjectName() const;
|
std::string GetProjectName() const;
|
||||||
|
|
||||||
/** Compute the language used to compile the given source file. */
|
/** Compute the language used to compile the given source file. */
|
||||||
@ -532,6 +578,33 @@ protected:
|
|||||||
bool BackwardsCompatibilityFinal;
|
bool BackwardsCompatibilityFinal;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* See LinearGetSourceFileWithOutput for background information
|
||||||
|
*/
|
||||||
|
cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generalized old version of GetSourceFileWithOutput kept for
|
||||||
|
* backward-compatibility. It implements a linear search and supports
|
||||||
|
* relative file paths. It is used as a fall back by GetSourceFileWithOutput
|
||||||
|
* and GetSourcesWithOutput.
|
||||||
|
*/
|
||||||
|
cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
|
||||||
|
cmSourceOutputKind kind,
|
||||||
|
bool& byproduct) const;
|
||||||
|
struct SourceEntry
|
||||||
|
{
|
||||||
|
cmSourcesWithOutput Sources;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A map for fast output to input look up.
|
||||||
|
using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
|
||||||
|
OutputToSourceMap OutputToSource;
|
||||||
|
|
||||||
|
void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target);
|
||||||
|
void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
|
||||||
|
bool byproduct);
|
||||||
|
|
||||||
void AddSharedFlags(std::string& flags, const std::string& lang,
|
void AddSharedFlags(std::string& flags, const std::string& lang,
|
||||||
bool shared);
|
bool shared);
|
||||||
bool GetShouldUseOldFlags(bool shared, const std::string& lang) const;
|
bool GetShouldUseOldFlags(bool shared, const std::string& lang) const;
|
||||||
|
@ -2145,191 +2145,6 @@ cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
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, 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 (const auto& src : this->SourceFiles) {
|
|
||||||
// Does this source file have a custom command?
|
|
||||||
if (src->GetCustomCommand()) {
|
|
||||||
// Does the output of the custom command match the source file name?
|
|
||||||
if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
|
|
||||||
// Return the first matching output.
|
|
||||||
return src.get();
|
|
||||||
}
|
|
||||||
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.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Did we find a byproduct?
|
|
||||||
byproduct = fallback != nullptr;
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
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() &&
|
|
||||||
(!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, a PRE_BUILD, PRE_LINK, or POST_BUILD
|
|
||||||
// command of a target, or a not yet created custom command.
|
|
||||||
return o->second.Sources.Source;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cmMakefile::AddTargetByproducts(
|
|
||||||
cmTarget* target, const std::vector<std::string>& byproducts)
|
|
||||||
{
|
|
||||||
for (std::string const& o : byproducts) {
|
|
||||||
this->UpdateOutputToSourceMap(o, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cmMakefile::AddSourceOutputs(cmSourceFile* source,
|
|
||||||
const std::vector<std::string>& outputs,
|
|
||||||
const std::vector<std::string>& byproducts)
|
|
||||||
{
|
|
||||||
for (std::string const& o : outputs) {
|
|
||||||
this->UpdateOutputToSourceMap(o, source, false);
|
|
||||||
}
|
|
||||||
for (std::string const& o : byproducts) {
|
|
||||||
this->UpdateOutputToSourceMap(o, source, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
|
|
||||||
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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(CMAKE_BOOTSTRAP)
|
#if !defined(CMAKE_BOOTSTRAP)
|
||||||
|
@ -59,24 +59,6 @@ class cmTestGenerator;
|
|||||||
class cmVariableWatch;
|
class cmVariableWatch;
|
||||||
class cmake;
|
class cmake;
|
||||||
|
|
||||||
/** Flag if byproducts shall also be considered. */
|
|
||||||
enum class cmSourceOutputKind
|
|
||||||
{
|
|
||||||
OutputOnly,
|
|
||||||
OutputOrByproduct
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Target and source file which have a specific output. */
|
|
||||||
struct cmSourcesWithOutput
|
|
||||||
{
|
|
||||||
/** Target with byproduct. */
|
|
||||||
cmTarget* Target = nullptr;
|
|
||||||
|
|
||||||
/** Source file with output or byproduct. */
|
|
||||||
cmSourceFile* Source = nullptr;
|
|
||||||
bool SourceIsByproduct = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A type-safe wrapper for a string representing a directory id. */
|
/** A type-safe wrapper for a string representing a directory id. */
|
||||||
class cmDirectoryId
|
class cmDirectoryId
|
||||||
{
|
{
|
||||||
@ -230,19 +212,6 @@ public:
|
|||||||
const cmImplicitDependsList& implicit_depends,
|
const cmImplicitDependsList& implicit_depends,
|
||||||
const cmCustomCommandLines& commandLines);
|
const cmCustomCommandLines& commandLines);
|
||||||
|
|
||||||
/**
|
|
||||||
* Add target byproducts.
|
|
||||||
*/
|
|
||||||
void AddTargetByproducts(cmTarget* target,
|
|
||||||
const std::vector<std::string>& byproducts);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add source file outputs.
|
|
||||||
*/
|
|
||||||
void AddSourceOutputs(cmSourceFile* source,
|
|
||||||
const std::vector<std::string>& outputs,
|
|
||||||
const std::vector<std::string>& byproducts);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a define flag to the build.
|
* Add a define flag to the build.
|
||||||
*/
|
*/
|
||||||
@ -753,20 +722,10 @@ public:
|
|||||||
return this->SourceFiles;
|
return this->SourceFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
std::vector<cmTarget*> const& GetOrderedTargets() const
|
||||||
* Return the target if the provided source name is a byproduct of a utility
|
{
|
||||||
* target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
|
return this->OrderedTargets;
|
||||||
* Return the source file which has the provided source name as output.
|
}
|
||||||
*/
|
|
||||||
cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is there a source file that has the provided source name as an output?
|
|
||||||
* If so then return it.
|
|
||||||
*/
|
|
||||||
cmSourceFile* GetSourceFileWithOutput(
|
|
||||||
const std::string& name,
|
|
||||||
cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
|
|
||||||
|
|
||||||
//! Add a new cmTest to the list of tests for this makefile.
|
//! Add a new cmTest to the list of tests for this makefile.
|
||||||
cmTest* CreateTest(const std::string& testName);
|
cmTest* CreateTest(const std::string& testName);
|
||||||
@ -983,8 +942,7 @@ protected:
|
|||||||
mutable cmTargetMap Targets;
|
mutable cmTargetMap Targets;
|
||||||
std::map<std::string, std::string> AliasTargets;
|
std::map<std::string, std::string> AliasTargets;
|
||||||
|
|
||||||
using TargetsVec = std::vector<cmTarget*>;
|
std::vector<cmTarget*> OrderedTargets;
|
||||||
TargetsVec OrderedTargets;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<cmSourceFile>> SourceFiles;
|
std::vector<std::unique_ptr<cmSourceFile>> SourceFiles;
|
||||||
|
|
||||||
@ -1134,34 +1092,6 @@ private:
|
|||||||
std::vector<BT<GeneratorAction>> GeneratorActions;
|
std::vector<BT<GeneratorAction>> GeneratorActions;
|
||||||
bool GeneratorActionsInvoked = false;
|
bool GeneratorActionsInvoked = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* See LinearGetSourceFileWithOutput for background information
|
|
||||||
*/
|
|
||||||
cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generalized old version of GetSourceFileWithOutput kept for
|
|
||||||
* backward-compatibility. It implements a linear search and supports
|
|
||||||
* relative file paths. It is used as a fall back by GetSourceFileWithOutput
|
|
||||||
* and GetSourcesWithOutput.
|
|
||||||
*/
|
|
||||||
cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
|
|
||||||
cmSourceOutputKind kind,
|
|
||||||
bool& byproduct) const;
|
|
||||||
|
|
||||||
struct SourceEntry
|
|
||||||
{
|
|
||||||
cmSourcesWithOutput Sources;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A map for fast output to input look up.
|
|
||||||
using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
|
|
||||||
OutputToSourceMap OutputToSource;
|
|
||||||
|
|
||||||
void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target);
|
|
||||||
void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
|
|
||||||
bool byproduct);
|
|
||||||
|
|
||||||
bool CheckSystemVars;
|
bool CheckSystemVars;
|
||||||
bool CheckCMP0000;
|
bool CheckCMP0000;
|
||||||
std::set<std::string> WarnedCMP0074;
|
std::set<std::string> WarnedCMP0074;
|
||||||
|
Loading…
Reference in New Issue
Block a user