Move TraceDependencies to cmGeneratorTarget.

This commit is contained in:
Stephen Kelly 2012-10-11 00:57:11 +02:00
parent fa03777626
commit 07f5788385
6 changed files with 318 additions and 317 deletions

View File

@ -19,6 +19,8 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionDAGChecker.h"
#include <queue>
//----------------------------------------------------------------------------
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t)
{
@ -45,6 +47,18 @@ const char *cmGeneratorTarget::GetProperty(const char *prop)
return this->Target->GetProperty(prop);
}
//----------------------------------------------------------------------------
std::vector<cmSourceFile*> const*
cmGeneratorTarget::GetSourceDepends(cmSourceFile* sf)
{
SourceEntriesType::iterator i = this->SourceEntries.find(sf);
if(i != this->SourceEntries.end())
{
return &i->second.Depends;
}
return 0;
}
//----------------------------------------------------------------------------
bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir,
const char *config)
@ -269,6 +283,285 @@ void cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs)
}
}
//----------------------------------------------------------------------------
class cmTargetTraceDependencies
{
public:
cmTargetTraceDependencies(cmGeneratorTarget* target);
void Trace();
private:
cmTarget* Target;
cmGeneratorTarget* GeneratorTarget;
cmMakefile* Makefile;
cmGlobalGenerator* GlobalGenerator;
typedef cmGeneratorTarget::SourceEntry SourceEntry;
SourceEntry* CurrentEntry;
std::queue<cmSourceFile*> SourceQueue;
std::set<cmSourceFile*> SourcesQueued;
typedef std::map<cmStdString, cmSourceFile*> NameMapType;
NameMapType NameMap;
void QueueSource(cmSourceFile* sf);
void FollowName(std::string const& name);
void FollowNames(std::vector<std::string> const& names);
bool IsUtility(std::string const& dep);
void CheckCustomCommand(cmCustomCommand const& cc);
void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
};
//----------------------------------------------------------------------------
cmTargetTraceDependencies
::cmTargetTraceDependencies(cmGeneratorTarget* target):
Target(target->Target), GeneratorTarget(target)
{
// Convenience.
this->Makefile = this->Target->GetMakefile();
this->GlobalGenerator =
this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
this->CurrentEntry = 0;
// Queue all the source files already specified for the target.
std::vector<cmSourceFile*> const& sources = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
si != sources.end(); ++si)
{
this->QueueSource(*si);
}
// Queue pre-build, pre-link, and post-build rule dependencies.
this->CheckCustomCommands(this->Target->GetPreBuildCommands());
this->CheckCustomCommands(this->Target->GetPreLinkCommands());
this->CheckCustomCommands(this->Target->GetPostBuildCommands());
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::Trace()
{
// Process one dependency at a time until the queue is empty.
while(!this->SourceQueue.empty())
{
// Get the next source from the queue.
cmSourceFile* sf = this->SourceQueue.front();
this->SourceQueue.pop();
this->CurrentEntry = &this->GeneratorTarget->SourceEntries[sf];
// Queue dependencies added explicitly by the user.
if(const char* additionalDeps = sf->GetProperty("OBJECT_DEPENDS"))
{
std::vector<std::string> objDeps;
cmSystemTools::ExpandListArgument(additionalDeps, objDeps);
this->FollowNames(objDeps);
}
// Queue the source needed to generate this file, if any.
this->FollowName(sf->GetFullPath());
// Queue dependencies added programatically by commands.
this->FollowNames(sf->GetDepends());
// Queue custom command dependencies.
if(cmCustomCommand const* cc = sf->GetCustomCommand())
{
this->CheckCustomCommand(*cc);
}
}
this->CurrentEntry = 0;
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
{
if(this->SourcesQueued.insert(sf).second)
{
this->SourceQueue.push(sf);
// Make sure this file is in the target.
this->Target->AddSourceFile(sf);
}
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::FollowName(std::string const& name)
{
NameMapType::iterator i = this->NameMap.find(name);
if(i == this->NameMap.end())
{
// Check if we know how to generate this file.
cmSourceFile* sf = this->Makefile->GetSourceFileWithOutput(name.c_str());
NameMapType::value_type entry(name, sf);
i = this->NameMap.insert(entry).first;
}
if(cmSourceFile* sf = i->second)
{
// Record the dependency we just followed.
if(this->CurrentEntry)
{
this->CurrentEntry->Depends.push_back(sf);
}
this->QueueSource(sf);
}
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies::FollowNames(std::vector<std::string> const& names)
{
for(std::vector<std::string>::const_iterator i = names.begin();
i != names.end(); ++i)
{
this->FollowName(*i);
}
}
//----------------------------------------------------------------------------
bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
{
// Dependencies on targets (utilities) are supposed to be named by
// just the target name. However for compatibility we support
// naming the output file generated by the target (assuming there is
// no output-name property which old code would not have set). In
// that case the target name will be the file basename of the
// dependency.
std::string util = cmSystemTools::GetFilenameName(dep);
if(cmSystemTools::GetFilenameLastExtension(util) == ".exe")
{
util = cmSystemTools::GetFilenameWithoutLastExtension(util);
}
// Check for a target with this name.
if(cmTarget* t = this->Makefile->FindTargetToUse(util.c_str()))
{
// If we find the target and the dep was given as a full path,
// then make sure it was not a full path to something else, and
// the fact that the name matched a target was just a coincidence.
if(cmSystemTools::FileIsFullPath(dep.c_str()))
{
if(t->GetType() >= cmTarget::EXECUTABLE &&
t->GetType() <= cmTarget::MODULE_LIBRARY)
{
// This is really only for compatibility so we do not need to
// worry about configuration names and output names.
std::string tLocation = t->GetLocation(0);
tLocation = cmSystemTools::GetFilenamePath(tLocation);
std::string depLocation = cmSystemTools::GetFilenamePath(dep);
depLocation = cmSystemTools::CollapseFullPath(depLocation.c_str());
tLocation = cmSystemTools::CollapseFullPath(tLocation.c_str());
if(depLocation == tLocation)
{
this->Target->AddUtility(util.c_str());
return true;
}
}
}
else
{
// The original name of the dependency was not a full path. It
// must name a target, so add the target-level dependency.
this->Target->AddUtility(util.c_str());
return true;
}
}
// The dependency does not name a target built in this project.
return false;
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies
::CheckCustomCommand(cmCustomCommand const& cc)
{
// Transform command names that reference targets built in this
// project to corresponding target-level dependencies.
cmGeneratorExpression ge(cc.GetBacktrace());
// Add target-level dependencies referenced by generator expressions.
std::set<cmTarget*> targets;
for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
cit != cc.GetCommandLines().end(); ++cit)
{
std::string const& command = *cit->begin();
// Check for a target with this name.
if(cmTarget* t = this->Makefile->FindTargetToUse(command.c_str()))
{
if(t->GetType() == cmTarget::EXECUTABLE)
{
// The command refers to an executable target built in
// this project. Add the target-level dependency to make
// sure the executable is up to date before this custom
// command possibly runs.
this->Target->AddUtility(command.c_str());
}
}
// Check for target references in generator expressions.
for(cmCustomCommandLine::const_iterator cli = cit->begin();
cli != cit->end(); ++cli)
{
const cmsys::auto_ptr<cmCompiledGeneratorExpression> cge
= ge.Parse(*cli);
cge->Evaluate(this->Makefile, 0, true);
std::set<cmTarget*> geTargets = cge->GetTargets();
for(std::set<cmTarget*>::const_iterator it = geTargets.begin();
it != geTargets.end(); ++it)
{
targets.insert(*it);
}
}
}
for(std::set<cmTarget*>::iterator ti = targets.begin();
ti != targets.end(); ++ti)
{
this->Target->AddUtility((*ti)->GetName());
}
// Queue the custom command dependencies.
std::vector<std::string> const& depends = cc.GetDepends();
for(std::vector<std::string>::const_iterator di = depends.begin();
di != depends.end(); ++di)
{
std::string const& dep = *di;
if(!this->IsUtility(dep))
{
// The dependency does not name a target and may be a file we
// know how to generate. Queue it.
this->FollowName(dep);
}
}
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies
::CheckCustomCommands(const std::vector<cmCustomCommand>& commands)
{
for(std::vector<cmCustomCommand>::const_iterator cli = commands.begin();
cli != commands.end(); ++cli)
{
this->CheckCustomCommand(*cli);
}
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::TraceDependencies()
{
// CMake-generated targets have no dependencies to trace. Normally tracing
// would find nothing anyway, but when building CMake itself the "install"
// target command ends up referencing the "cmake" target but we do not
// really want the dependency because "install" depend on "all" anyway.
if(this->GetType() == cmTarget::GLOBAL_TARGET)
{
return;
}
// Use a helper object to trace the dependencies.
cmTargetTraceDependencies tracer(this);
tracer.Trace();
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetAppleArchs(const char* config,
std::vector<std::string>& archVec)

View File

@ -77,9 +77,22 @@ public:
/** Add the target output files to the global generator manifest. */
void GenerateTargetManifest(const char* config);
/**
* Trace through the source files in this target and add al source files
* that they depend on, used by all generators
*/
void TraceDependencies();
void ClassifySources();
void LookupObjectLibraries();
/** Get sources that must be built before the given source. */
std::vector<cmSourceFile*> const* GetSourceDepends(cmSourceFile* sf);
struct SourceEntry { std::vector<cmSourceFile*> Depends; };
typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType;
SourceEntriesType SourceEntries;
private:
std::map<std::string, std::vector<std::string> > SystemIncludesCache;

View File

@ -257,10 +257,11 @@ void cmLocalGenerator::ConfigureFinalPass()
void cmLocalGenerator::TraceDependencies()
{
// Generate the rule files for each target.
cmTargets& targets = this->Makefile->GetTargets();
for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
cmGeneratorTargetsType targets = this->Makefile->GetGeneratorTargets();
for(cmGeneratorTargetsType::iterator t = targets.begin();
t != targets.end(); ++t)
{
t->second.TraceDependencies();
t->second->TraceDependencies();
}
}

View File

@ -22,7 +22,6 @@
#include <cmsys/RegularExpression.hxx>
#include <map>
#include <set>
#include <queue>
#include <stdlib.h> // required for atof
#include <assert.h>
@ -84,12 +83,9 @@ public:
{
this->SourceFileFlagsConstructed = false;
}
cmTargetInternals(cmTargetInternals const& r)
cmTargetInternals(cmTargetInternals const&)
{
this->SourceFileFlagsConstructed = false;
// Only some of these entries are part of the object state.
// Others not copied here are result caches.
this->SourceEntries = r.SourceEntries;
}
~cmTargetInternals();
typedef cmTarget::SourceFileFlags SourceFileFlags;
@ -125,10 +121,6 @@ public:
LinkClosureMapType;
LinkClosureMapType LinkClosureMap;
struct SourceEntry { std::vector<cmSourceFile*> Depends; };
typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType;
SourceEntriesType SourceEntries;
struct TargetPropertyEntry {
TargetPropertyEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge,
const std::string &targetName = std::string())
@ -488,285 +480,6 @@ bool cmTarget::IsBundleOnApple()
this->IsCFBundleOnApple();
}
//----------------------------------------------------------------------------
class cmTargetTraceDependencies
{
public:
cmTargetTraceDependencies(cmTarget* target, cmTargetInternals* internal);
void Trace();
private:
cmTarget* Target;
cmTargetInternals* Internal;
cmMakefile* Makefile;
cmGlobalGenerator* GlobalGenerator;
typedef cmTargetInternals::SourceEntry SourceEntry;
SourceEntry* CurrentEntry;
std::queue<cmSourceFile*> SourceQueue;
std::set<cmSourceFile*> SourcesQueued;
typedef std::map<cmStdString, cmSourceFile*> NameMapType;
NameMapType NameMap;
void QueueSource(cmSourceFile* sf);
void FollowName(std::string const& name);
void FollowNames(std::vector<std::string> const& names);
bool IsUtility(std::string const& dep);
void CheckCustomCommand(cmCustomCommand const& cc);
void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
};
//----------------------------------------------------------------------------
cmTargetTraceDependencies
::cmTargetTraceDependencies(cmTarget* target, cmTargetInternals* internal):
Target(target), Internal(internal)
{
// Convenience.
this->Makefile = this->Target->GetMakefile();
this->GlobalGenerator =
this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
this->CurrentEntry = 0;
// Queue all the source files already specified for the target.
std::vector<cmSourceFile*> const& sources = this->Target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
si != sources.end(); ++si)
{
this->QueueSource(*si);
}
// Queue pre-build, pre-link, and post-build rule dependencies.
this->CheckCustomCommands(this->Target->GetPreBuildCommands());
this->CheckCustomCommands(this->Target->GetPreLinkCommands());
this->CheckCustomCommands(this->Target->GetPostBuildCommands());
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::Trace()
{
// Process one dependency at a time until the queue is empty.
while(!this->SourceQueue.empty())
{
// Get the next source from the queue.
cmSourceFile* sf = this->SourceQueue.front();
this->SourceQueue.pop();
this->CurrentEntry = &this->Internal->SourceEntries[sf];
// Queue dependencies added explicitly by the user.
if(const char* additionalDeps = sf->GetProperty("OBJECT_DEPENDS"))
{
std::vector<std::string> objDeps;
cmSystemTools::ExpandListArgument(additionalDeps, objDeps);
this->FollowNames(objDeps);
}
// Queue the source needed to generate this file, if any.
this->FollowName(sf->GetFullPath());
// Queue dependencies added programatically by commands.
this->FollowNames(sf->GetDepends());
// Queue custom command dependencies.
if(cmCustomCommand const* cc = sf->GetCustomCommand())
{
this->CheckCustomCommand(*cc);
}
}
this->CurrentEntry = 0;
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
{
if(this->SourcesQueued.insert(sf).second)
{
this->SourceQueue.push(sf);
// Make sure this file is in the target.
this->Target->AddSourceFile(sf);
}
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::FollowName(std::string const& name)
{
NameMapType::iterator i = this->NameMap.find(name);
if(i == this->NameMap.end())
{
// Check if we know how to generate this file.
cmSourceFile* sf = this->Makefile->GetSourceFileWithOutput(name.c_str());
NameMapType::value_type entry(name, sf);
i = this->NameMap.insert(entry).first;
}
if(cmSourceFile* sf = i->second)
{
// Record the dependency we just followed.
if(this->CurrentEntry)
{
this->CurrentEntry->Depends.push_back(sf);
}
this->QueueSource(sf);
}
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies::FollowNames(std::vector<std::string> const& names)
{
for(std::vector<std::string>::const_iterator i = names.begin();
i != names.end(); ++i)
{
this->FollowName(*i);
}
}
//----------------------------------------------------------------------------
bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
{
// Dependencies on targets (utilities) are supposed to be named by
// just the target name. However for compatibility we support
// naming the output file generated by the target (assuming there is
// no output-name property which old code would not have set). In
// that case the target name will be the file basename of the
// dependency.
std::string util = cmSystemTools::GetFilenameName(dep);
if(cmSystemTools::GetFilenameLastExtension(util) == ".exe")
{
util = cmSystemTools::GetFilenameWithoutLastExtension(util);
}
// Check for a target with this name.
if(cmTarget* t = this->Makefile->FindTargetToUse(util.c_str()))
{
// If we find the target and the dep was given as a full path,
// then make sure it was not a full path to something else, and
// the fact that the name matched a target was just a coincidence.
if(cmSystemTools::FileIsFullPath(dep.c_str()))
{
if(t->GetType() >= cmTarget::EXECUTABLE &&
t->GetType() <= cmTarget::MODULE_LIBRARY)
{
// This is really only for compatibility so we do not need to
// worry about configuration names and output names.
std::string tLocation = t->GetLocation(0);
tLocation = cmSystemTools::GetFilenamePath(tLocation);
std::string depLocation = cmSystemTools::GetFilenamePath(dep);
depLocation = cmSystemTools::CollapseFullPath(depLocation.c_str());
tLocation = cmSystemTools::CollapseFullPath(tLocation.c_str());
if(depLocation == tLocation)
{
this->Target->AddUtility(util.c_str());
return true;
}
}
}
else
{
// The original name of the dependency was not a full path. It
// must name a target, so add the target-level dependency.
this->Target->AddUtility(util.c_str());
return true;
}
}
// The dependency does not name a target built in this project.
return false;
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies
::CheckCustomCommand(cmCustomCommand const& cc)
{
// Transform command names that reference targets built in this
// project to corresponding target-level dependencies.
cmGeneratorExpression ge(cc.GetBacktrace());
// Add target-level dependencies referenced by generator expressions.
std::set<cmTarget*> targets;
for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
cit != cc.GetCommandLines().end(); ++cit)
{
std::string const& command = *cit->begin();
// Check for a target with this name.
if(cmTarget* t = this->Makefile->FindTargetToUse(command.c_str()))
{
if(t->GetType() == cmTarget::EXECUTABLE)
{
// The command refers to an executable target built in
// this project. Add the target-level dependency to make
// sure the executable is up to date before this custom
// command possibly runs.
this->Target->AddUtility(command.c_str());
}
}
// Check for target references in generator expressions.
for(cmCustomCommandLine::const_iterator cli = cit->begin();
cli != cit->end(); ++cli)
{
const cmsys::auto_ptr<cmCompiledGeneratorExpression> cge
= ge.Parse(*cli);
cge->Evaluate(this->Makefile, 0, true);
std::set<cmTarget*> geTargets = cge->GetTargets();
for(std::set<cmTarget*>::const_iterator it = geTargets.begin();
it != geTargets.end(); ++it)
{
targets.insert(*it);
}
}
}
for(std::set<cmTarget*>::iterator ti = targets.begin();
ti != targets.end(); ++ti)
{
this->Target->AddUtility((*ti)->GetName());
}
// Queue the custom command dependencies.
std::vector<std::string> const& depends = cc.GetDepends();
for(std::vector<std::string>::const_iterator di = depends.begin();
di != depends.end(); ++di)
{
std::string const& dep = *di;
if(!this->IsUtility(dep))
{
// The dependency does not name a target and may be a file we
// know how to generate. Queue it.
this->FollowName(dep);
}
}
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies
::CheckCustomCommands(const std::vector<cmCustomCommand>& commands)
{
for(std::vector<cmCustomCommand>::const_iterator cli = commands.begin();
cli != commands.end(); ++cli)
{
this->CheckCustomCommand(*cli);
}
}
//----------------------------------------------------------------------------
void cmTarget::TraceDependencies()
{
// CMake-generated targets have no dependencies to trace. Normally tracing
// would find nothing anyway, but when building CMake itself the "install"
// target command ends up referencing the "cmake" target but we do not
// really want the dependency because "install" depend on "all" anyway.
if(this->GetType() == cmTarget::GLOBAL_TARGET)
{
return;
}
// Use a helper object to trace the dependencies.
cmTargetTraceDependencies tracer(this, this->Internal.Get());
tracer.Trace();
}
//----------------------------------------------------------------------------
bool cmTarget::FindSourceFiles()
{
@ -798,28 +511,13 @@ std::vector<cmSourceFile*> const& cmTarget::GetSourceFiles()
//----------------------------------------------------------------------------
void cmTarget::AddSourceFile(cmSourceFile* sf)
{
typedef cmTargetInternals::SourceEntriesType SourceEntriesType;
if (std::find(this->SourceFiles.begin(), this->SourceFiles.end(), sf)
== this->SourceFiles.end())
{
typedef cmTargetInternals::SourceEntry SourceEntry;
this->SourceFiles.push_back(sf);
}
}
//----------------------------------------------------------------------------
std::vector<cmSourceFile*> const*
cmTarget::GetSourceDepends(cmSourceFile* sf)
{
typedef cmTargetInternals::SourceEntriesType SourceEntriesType;
SourceEntriesType::iterator i = this->Internal->SourceEntries.find(sf);
if(i != this->Internal->SourceEntries.end())
{
return &i->second.Depends;
}
return 0;
}
//----------------------------------------------------------------------------
void cmTarget::AddSources(std::vector<std::string> const& srcs)
{

View File

@ -34,6 +34,8 @@ class cmGlobalGenerator;
class cmComputeLinkInformation;
class cmListFileBacktrace;
class cmTarget;
class cmGeneratorTarget;
class cmTargetTraceDependencies;
struct cmTargetLinkInformationMap:
public std::map<std::pair<cmTarget*, std::string>, cmComputeLinkInformation*>
@ -128,9 +130,6 @@ public:
return this->ObjectLibraries;
}
/** Get sources that must be built before the given source. */
std::vector<cmSourceFile*> const* GetSourceDepends(cmSourceFile* sf);
/**
* Flags for a given source file as used in this target. Typically assigned
* via SET_TARGET_PROPERTIES when the property is a list of source files.
@ -346,12 +345,6 @@ public:
is returned if the property is not set or cannot be parsed. */
void GetTargetVersion(bool soversion, int& major, int& minor, int& patch);
/**
* Trace through the source files in this target and add al source files
* that they depend on, used by all generators
*/
void TraceDependencies();
/**
* Make sure the full path to all source files is known.
*/
@ -732,6 +725,8 @@ private:
// Internal representation details.
friend class cmTargetInternals;
friend class cmGeneratorTarget;
friend class cmTargetTraceDependencies;
cmTargetInternalPointer Internal;
void ConstructSourceFileFlags();

View File

@ -562,7 +562,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommand(cmSourceFile* sf)
if(this->SourcesVisited.insert(sf).second)
{
if(std::vector<cmSourceFile*> const* depends =
this->Target->GetSourceDepends(sf))
this->GeneratorTarget->GetSourceDepends(sf))
{
for(std::vector<cmSourceFile*>::const_iterator di = depends->begin();
di != depends->end(); ++di)
@ -1049,7 +1049,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources()
si = this->GeneratorTarget->ExternalObjects.begin();
si != this->GeneratorTarget->ExternalObjects.end(); ++si)
{
std::vector<cmSourceFile*> const* d=this->Target->GetSourceDepends(*si);
std::vector<cmSourceFile*> const* d =
this->GeneratorTarget->GetSourceDepends(*si);
this->WriteSource((d && !d->empty())? "None":"Object", *si);
}
}