Merge topic 'use-generator-target'
07f5788
Move TraceDependencies to cmGeneratorTarget.fa03777
Do not populate SourceEntries in AddSourceFile.
This commit is contained in:
commit
7a616e75b8
|
@ -19,6 +19,8 @@
|
||||||
#include "cmGeneratorExpression.h"
|
#include "cmGeneratorExpression.h"
|
||||||
#include "cmGeneratorExpressionDAGChecker.h"
|
#include "cmGeneratorExpressionDAGChecker.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t)
|
cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t)
|
||||||
{
|
{
|
||||||
|
@ -45,6 +47,18 @@ const char *cmGeneratorTarget::GetProperty(const char *prop)
|
||||||
return this->Target->GetProperty(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,
|
bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir,
|
||||||
const char *config)
|
const char *config)
|
||||||
|
@ -276,6 +290,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,
|
void cmGeneratorTarget::GetAppleArchs(const char* config,
|
||||||
std::vector<std::string>& archVec)
|
std::vector<std::string>& archVec)
|
||||||
|
|
|
@ -77,9 +77,22 @@ public:
|
||||||
/** Add the target output files to the global generator manifest. */
|
/** Add the target output files to the global generator manifest. */
|
||||||
void GenerateTargetManifest(const char* config);
|
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 ClassifySources();
|
||||||
void LookupObjectLibraries();
|
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:
|
private:
|
||||||
std::map<std::string, std::vector<std::string> > SystemIncludesCache;
|
std::map<std::string, std::vector<std::string> > SystemIncludesCache;
|
||||||
|
|
||||||
|
|
|
@ -257,10 +257,11 @@ void cmLocalGenerator::ConfigureFinalPass()
|
||||||
void cmLocalGenerator::TraceDependencies()
|
void cmLocalGenerator::TraceDependencies()
|
||||||
{
|
{
|
||||||
// Generate the rule files for each target.
|
// Generate the rule files for each target.
|
||||||
cmTargets& targets = this->Makefile->GetTargets();
|
cmGeneratorTargetsType targets = this->Makefile->GetGeneratorTargets();
|
||||||
for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
|
for(cmGeneratorTargetsType::iterator t = targets.begin();
|
||||||
|
t != targets.end(); ++t)
|
||||||
{
|
{
|
||||||
t->second.TraceDependencies();
|
t->second->TraceDependencies();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include <cmsys/RegularExpression.hxx>
|
#include <cmsys/RegularExpression.hxx>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <queue>
|
|
||||||
#include <stdlib.h> // required for atof
|
#include <stdlib.h> // required for atof
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -84,12 +83,9 @@ public:
|
||||||
{
|
{
|
||||||
this->SourceFileFlagsConstructed = false;
|
this->SourceFileFlagsConstructed = false;
|
||||||
}
|
}
|
||||||
cmTargetInternals(cmTargetInternals const& r)
|
cmTargetInternals(cmTargetInternals const&)
|
||||||
{
|
{
|
||||||
this->SourceFileFlagsConstructed = false;
|
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();
|
~cmTargetInternals();
|
||||||
typedef cmTarget::SourceFileFlags SourceFileFlags;
|
typedef cmTarget::SourceFileFlags SourceFileFlags;
|
||||||
|
@ -125,10 +121,6 @@ public:
|
||||||
LinkClosureMapType;
|
LinkClosureMapType;
|
||||||
LinkClosureMapType LinkClosureMap;
|
LinkClosureMapType LinkClosureMap;
|
||||||
|
|
||||||
struct SourceEntry { std::vector<cmSourceFile*> Depends; };
|
|
||||||
typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType;
|
|
||||||
SourceEntriesType SourceEntries;
|
|
||||||
|
|
||||||
struct TargetPropertyEntry {
|
struct TargetPropertyEntry {
|
||||||
TargetPropertyEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge,
|
TargetPropertyEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge,
|
||||||
const std::string &targetName = std::string())
|
const std::string &targetName = std::string())
|
||||||
|
@ -492,285 +484,6 @@ bool cmTarget::IsBundleOnApple()
|
||||||
this->IsCFBundleOnApple();
|
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()
|
bool cmTarget::FindSourceFiles()
|
||||||
{
|
{
|
||||||
|
@ -802,30 +515,13 @@ std::vector<cmSourceFile*> const& cmTarget::GetSourceFiles()
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmTarget::AddSourceFile(cmSourceFile* sf)
|
void cmTarget::AddSourceFile(cmSourceFile* sf)
|
||||||
{
|
{
|
||||||
typedef cmTargetInternals::SourceEntriesType SourceEntriesType;
|
if (std::find(this->SourceFiles.begin(), this->SourceFiles.end(), sf)
|
||||||
SourceEntriesType::iterator i = this->Internal->SourceEntries.find(sf);
|
== this->SourceFiles.end())
|
||||||
if(i == this->Internal->SourceEntries.end())
|
|
||||||
{
|
{
|
||||||
typedef cmTargetInternals::SourceEntry SourceEntry;
|
|
||||||
SourceEntriesType::value_type entry(sf, SourceEntry());
|
|
||||||
i = this->Internal->SourceEntries.insert(entry).first;
|
|
||||||
this->SourceFiles.push_back(sf);
|
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)
|
void cmTarget::AddSources(std::vector<std::string> const& srcs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,6 +34,8 @@ class cmGlobalGenerator;
|
||||||
class cmComputeLinkInformation;
|
class cmComputeLinkInformation;
|
||||||
class cmListFileBacktrace;
|
class cmListFileBacktrace;
|
||||||
class cmTarget;
|
class cmTarget;
|
||||||
|
class cmGeneratorTarget;
|
||||||
|
class cmTargetTraceDependencies;
|
||||||
|
|
||||||
struct cmTargetLinkInformationMap:
|
struct cmTargetLinkInformationMap:
|
||||||
public std::map<std::pair<cmTarget*, std::string>, cmComputeLinkInformation*>
|
public std::map<std::pair<cmTarget*, std::string>, cmComputeLinkInformation*>
|
||||||
|
@ -128,9 +130,6 @@ public:
|
||||||
return this->ObjectLibraries;
|
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
|
* 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.
|
* 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. */
|
is returned if the property is not set or cannot be parsed. */
|
||||||
void GetTargetVersion(bool soversion, int& major, int& minor, int& patch);
|
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.
|
* Make sure the full path to all source files is known.
|
||||||
*/
|
*/
|
||||||
|
@ -732,6 +725,8 @@ private:
|
||||||
|
|
||||||
// Internal representation details.
|
// Internal representation details.
|
||||||
friend class cmTargetInternals;
|
friend class cmTargetInternals;
|
||||||
|
friend class cmGeneratorTarget;
|
||||||
|
friend class cmTargetTraceDependencies;
|
||||||
cmTargetInternalPointer Internal;
|
cmTargetInternalPointer Internal;
|
||||||
|
|
||||||
void ConstructSourceFileFlags();
|
void ConstructSourceFileFlags();
|
||||||
|
|
|
@ -562,7 +562,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommand(cmSourceFile* sf)
|
||||||
if(this->SourcesVisited.insert(sf).second)
|
if(this->SourcesVisited.insert(sf).second)
|
||||||
{
|
{
|
||||||
if(std::vector<cmSourceFile*> const* depends =
|
if(std::vector<cmSourceFile*> const* depends =
|
||||||
this->Target->GetSourceDepends(sf))
|
this->GeneratorTarget->GetSourceDepends(sf))
|
||||||
{
|
{
|
||||||
for(std::vector<cmSourceFile*>::const_iterator di = depends->begin();
|
for(std::vector<cmSourceFile*>::const_iterator di = depends->begin();
|
||||||
di != depends->end(); ++di)
|
di != depends->end(); ++di)
|
||||||
|
@ -1049,7 +1049,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources()
|
||||||
si = this->GeneratorTarget->ExternalObjects.begin();
|
si = this->GeneratorTarget->ExternalObjects.begin();
|
||||||
si != this->GeneratorTarget->ExternalObjects.end(); ++si)
|
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);
|
this->WriteSource((d && !d->empty())? "None":"Object", *si);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue