summaryrefslogtreecommitdiffstats
path: root/Source/cmTarget.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmTarget.cxx')
-rw-r--r--Source/cmTarget.cxx471
1 files changed, 224 insertions, 247 deletions
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index e8b6fdb..46d4273 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -281,6 +281,7 @@ void cmTarget::DefineProperties(cmake *cm)
"An internal property used by some generators to record the name of "
"project or dsp file associated with this target.");
+#if 0
cm->DefineProperty
("OBJECT_FILES", cmProperty::TARGET,
"Used to get the resulting list of object files that make up a "
@@ -289,6 +290,7 @@ void cmTarget::DefineProperties(cmake *cm)
"into another library. It is a read only property. It "
"converts the source list for the target into a list of full "
"paths to object names that will be produced by the target.");
+#endif
#define CM_TARGET_FILE_TYPES_DOC \
"There are three kinds of target files that may be built: " \
@@ -414,288 +416,269 @@ void cmTarget::SetMakefile(cmMakefile* mf)
}
}
+//----------------------------------------------------------------------------
+class cmTargetTraceDependencies
+{
+public:
+ cmTargetTraceDependencies(cmTarget* target, const char* vsProjectFile);
+ void Trace();
+private:
+ cmTarget* Target;
+ cmMakefile* Makefile;
+ cmGlobalGenerator* GlobalGenerator;
+ std::queue<cmStdString> DependencyQueue;
+ std::set<cmStdString> DependenciesQueued;
+ std::set<cmSourceFile*> TargetSources;
+
+ void QueueOnce(std::string const& name);
+ void QueueOnce(std::vector<std::string> const& names);
+ void QueueDependencies(cmSourceFile* sf);
+ bool IsUtility(std::string const& dep);
+ void CheckCustomCommand(cmCustomCommand const& cc);
+ void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
+};
-void cmTarget::CheckForTargetsAsCommand(const cmCustomCommand& cc)
+//----------------------------------------------------------------------------
+cmTargetTraceDependencies
+::cmTargetTraceDependencies(cmTarget* target, const char* vsProjectFile):
+ Target(target)
{
- for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
- cit != cc.GetCommandLines().end(); ++cit )
+ // Convenience.
+ this->Makefile = this->Target->GetMakefile();
+ this->GlobalGenerator =
+ this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
+
+ // 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)
{
- std::string const& command = *cit->begin();
- // Look for a non-imported target with this name.
- if(cmTarget* t = this->Makefile->GetLocalGenerator()->
- GetGlobalGenerator()->FindTarget(0, command.c_str(), false))
+ // Queue the source file itself in case it is generated.
+ this->QueueOnce((*si)->GetFullPath());
+
+ // Queue the dependencies of the source file in case they are
+ // generated.
+ this->QueueDependencies(*si);
+
+ // Track the sources already known to the target.
+ this->TargetSources.insert(*si);
+ }
+
+ // Queue the VS project file to check dependencies on the rule to
+ // generate it.
+ if(vsProjectFile)
+ {
+ this->QueueOnce(vsProjectFile);
+ }
+
+ // 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->DependencyQueue.empty())
+ {
+ // Get the next dependency in from queue.
+ std::string dep = this->DependencyQueue.front();
+ this->DependencyQueue.pop();
+
+ // Check if we know how to generate this dependency.
+ if(cmSourceFile* sf =
+ this->Makefile->GetSourceFileWithOutput(dep.c_str()))
{
- if(t->GetType() == cmTarget::EXECUTABLE)
+ // Queue dependencies needed to generate this file.
+ this->QueueDependencies(sf);
+
+ // Make sure this file is in the target.
+ if(this->TargetSources.insert(sf).second)
{
- // 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->AddUtility(command.c_str());
+ this->Target->AddSourceFile(sf);
}
}
}
}
-void
-cmTarget
-::CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands)
+//----------------------------------------------------------------------------
+void cmTargetTraceDependencies::QueueOnce(std::string const& name)
{
- for ( std::vector<cmCustomCommand>::const_iterator cli = commands.begin();
- cli != commands.end();
- ++cli )
+ if(this->DependenciesQueued.insert(name).second)
{
- this->CheckForTargetsAsCommand(*cli);
+ this->DependencyQueue.push(name);
}
}
-
-void cmTarget::TraceVSDependencies(std::string projFile,
- cmMakefile *makefile)
-{
- // get the classes from the source lists then add them to the groups
- std::vector<cmSourceFile*> & classes = this->SourceFiles;
- // use a deck to keep track of processed source files
- std::queue<std::string> srcFilesToProcess;
- std::set<cmStdString> srcFilesQueued;
- std::string name;
- std::vector<cmSourceFile*> newClasses;
- for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
- i != classes.end(); ++i)
+//----------------------------------------------------------------------------
+void
+cmTargetTraceDependencies::QueueOnce(std::vector<std::string> const& names)
+{
+ for(std::vector<std::string>::const_iterator i = names.begin();
+ i != names.end(); ++i)
{
- name = (*i)->GetSourceName();
- if ((*i)->GetSourceExtension() != "rule")
- {
- name += ".";
- name += (*i)->GetSourceExtension();
- }
- srcFilesToProcess.push(name);
- srcFilesQueued.insert(name);
- // does this sourcefile have object depends on it?
- // If so then add them as well
- const char* additionalDeps = (*i)->GetProperty("OBJECT_DEPENDS");
- std::vector<std::string> depends = (*i)->GetDepends();
- if (additionalDeps || depends.size())
+ this->QueueOnce(*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 non-imported target with this name.
+ if(cmTarget* t =
+ this->GlobalGenerator->FindTarget(0, util.c_str(), false))
+ {
+ // 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(additionalDeps)
+ // 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)
{
- cmSystemTools::ExpandListArgument(additionalDeps, depends);
- }
- for(std::vector<std::string>::iterator id = depends.begin();
- id != depends.end(); ++id)
- {
- // if there is a custom rule to generate that dependency
- // then add it to the list
- cmSourceFile* outsf =
- makefile->GetSourceFileWithOutput(id->c_str());
- // if a source file was found then add it
- if (outsf &&
- (std::find(classes.begin(),classes.end(),outsf) == classes.end())
- &&
- (std::find(newClasses.begin(),newClasses.end(),outsf)
- == newClasses.end()))
- {
- // then add the source to this target and add it to the queue
- newClasses.push_back(outsf);
- name = outsf->GetSourceName();
- if (outsf->GetSourceExtension() != "rule")
- {
- name += ".";
- name += outsf->GetSourceExtension();
- }
- std::string temp =
- cmSystemTools::GetFilenamePath(outsf->GetFullPath());
- temp += "/";
- temp += name;
- // if it hasn't been processed
- if (srcFilesQueued.find(temp) == srcFilesQueued.end())
- {
- srcFilesToProcess.push(temp);
- srcFilesQueued.insert(temp);
- }
- }
+ 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;
+ }
}
- for(std::vector<cmSourceFile*>::const_iterator i = newClasses.begin();
- i != newClasses.end(); ++i)
+
+ // The dependency does not name a target built in this project.
+ return false;
+}
+
+//----------------------------------------------------------------------------
+void cmTargetTraceDependencies::QueueDependencies(cmSourceFile* sf)
+{
+ // Queue dependency added explicitly by the user.
+ if(const char* additionalDeps = sf->GetProperty("OBJECT_DEPENDS"))
{
- classes.push_back(*i);
+ std::vector<std::string> objDeps;
+ cmSystemTools::ExpandListArgument(additionalDeps, objDeps);
+ this->QueueOnce(objDeps);
}
-
- // add in the project file itself
- if (projFile.size())
+
+ // Queue dependencies added programatically by commands.
+ this->QueueOnce(sf->GetDepends());
+
+ // Queue custom command dependencies.
+ if(cmCustomCommand const* cc = sf->GetCustomCommand())
{
- srcFilesToProcess.push(projFile);
- srcFilesQueued.insert(projFile);
+ this->CheckCustomCommand(*cc);
}
- // add in the library depends for custom targets
- if (this->GetType() == cmTarget::UTILITY ||
- this->GetType() == cmTarget::GLOBAL_TARGET)
+
+}
+
+//----------------------------------------------------------------------------
+void
+cmTargetTraceDependencies
+::CheckCustomCommand(cmCustomCommand const& cc)
+{
+ // Transform command names that reference targets built in this
+ // project to corresponding target-level dependencies.
+ for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
+ cit != cc.GetCommandLines().end(); ++cit)
{
- for (std::vector<cmCustomCommand>::iterator ic =
- this->GetPostBuildCommands().begin();
- ic != this->GetPostBuildCommands().end(); ++ic)
+ std::string const& command = *cit->begin();
+ // Look for a non-imported target with this name.
+ if(cmTarget* t =
+ this->GlobalGenerator->FindTarget(0, command.c_str(), false))
{
- cmCustomCommand &c = *ic;
- for (std::vector<std::string>::const_iterator i
- = c.GetDepends().begin(); i != c.GetDepends().end(); ++i)
+ if(t->GetType() == cmTarget::EXECUTABLE)
{
- srcFilesToProcess.push(*i);
- srcFilesQueued.insert(*i);
+ // 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());
}
}
}
- this->CheckForTargetsAsCommand(this->GetPreBuildCommands());
- this->CheckForTargetsAsCommand(this->GetPreLinkCommands());
- this->CheckForTargetsAsCommand(this->GetPostBuildCommands());
-
- while (!srcFilesToProcess.empty())
+ // 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)
{
- // is this source the output of a custom command
- cmSourceFile* outsf =
- makefile->GetSourceFileWithOutput(srcFilesToProcess.front().c_str());
- if (outsf)
+ std::string const& dep = *di;
+ if(!this->IsUtility(dep))
{
- // is it not already in the target?
- if (std::find(classes.begin(),classes.end(),outsf) == classes.end())
- {
- // then add the source to this target and add it to the queue
- classes.push_back(outsf);
- name = outsf->GetSourceName();
- if (outsf->GetSourceExtension() != "rule")
- {
- name += ".";
- name += outsf->GetSourceExtension();
- }
- std::string temp =
- cmSystemTools::GetFilenamePath(outsf->GetFullPath());
- temp += "/";
- temp += name;
- // if it hasn't been processed
- if (srcFilesQueued.find(temp) == srcFilesQueued.end())
- {
- srcFilesToProcess.push(temp);
- srcFilesQueued.insert(temp);
- }
- }
-
- // Add target-level dependencies for the commands.
- this->CheckForTargetsAsCommand(*outsf->GetCustomCommand());
-
- // add its dependencies to the list to check
- for (unsigned int i = 0;
- i < outsf->GetCustomCommand()->GetDepends().size();
- ++i)
- {
- const std::string& fullName
- = outsf->GetCustomCommand()->GetDepends()[i];
- std::string dep = cmSystemTools::GetFilenameName(fullName);
- if (cmSystemTools::GetFilenameLastExtension(dep) == ".exe")
- {
- dep = cmSystemTools::GetFilenameWithoutLastExtension(dep);
- }
- bool isUtility = false;
- // Check for a non-imported target with this name.
- if(cmTarget* t = this->Makefile->GetLocalGenerator()->
- GetGlobalGenerator()->FindTarget(0, dep.c_str(), false))
- {
- // 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 coincident
- if(cmSystemTools::FileIsFullPath(fullName.c_str()))
- {
- std::string tLocation = t->GetLocation(0);
- tLocation = cmSystemTools::GetFilenamePath(tLocation);
- std::string depLocation = cmSystemTools::GetFilenamePath(
- std::string(fullName));
- depLocation =
- cmSystemTools::CollapseFullPath(depLocation.c_str());
- tLocation = cmSystemTools::CollapseFullPath(tLocation.c_str());
- if(depLocation == tLocation)
- {
- isUtility = true;
- }
- }
- // if it was not a full path then it must be a target
- else
- {
- isUtility = true;
- }
- }
- if(isUtility)
- {
- // The dependency refers to a target built in this project.
- // Add the target-level dependency to make sure the target
- // is up to date before this custom command possibly runs.
- this->AddUtility(dep.c_str());
- }
- else
- {
- if (srcFilesQueued.find(outsf->GetCustomCommand()->GetDepends()[i])
- == srcFilesQueued.end())
- {
- srcFilesToProcess.push
- (outsf->GetCustomCommand()->GetDepends()[i]);
- srcFilesQueued.insert(outsf->GetCustomCommand()->GetDepends()[i]);
- }
- }
- }
-
+ // The dependency does not name a target and may be a file we
+ // know how to generate. Queue it.
+ this->QueueOnce(dep);
}
- // finished with this SF move to the next
- srcFilesToProcess.pop();
}
}
-void cmTarget::GenerateSourceFilesFromSourceLists( cmMakefile &mf)
+//----------------------------------------------------------------------------
+void
+cmTargetTraceDependencies
+::CheckCustomCommands(const std::vector<cmCustomCommand>& commands)
{
- // only allow this to be called once
- // there is a lazy evaluation of this in ComputeObjectFiles,
- // that could break backwards compatibility with projects that
- // use old style source lists.
- if(this->SourceFiles.size() != 0)
+ for(std::vector<cmCustomCommand>::const_iterator cli = commands.begin();
+ cli != commands.end(); ++cli)
{
- return;
+ this->CheckCustomCommand(*cli);
}
- // for each src lists add the classes
- for (std::vector<std::string>::const_iterator s = this->SourceLists.begin();
- s != this->SourceLists.end(); ++s)
- {
- int done = 0;
- // replace any variables
- std::string temps = *s;
- mf.ExpandVariablesInString(temps);
+}
- // Next if one wasn't found then assume it is a single class
- // check to see if it is an existing source file
- if (!done)
- {
- cmSourceFile* sourceFile = mf.GetSource(temps.c_str());
- if ( sourceFile )
- {
- this->SourceFiles.push_back(sourceFile);
- done = 1;
- }
- }
-
- // if we still are not done, try to create the SourceFile structure
- if (!done)
- {
- cmSourceFile file;
- file.GetProperties().
- SetCMakeInstance(this->Makefile->GetCMakeInstance());
- file.SetProperty("ABSTRACT","0");
- file.SetName(temps.c_str(), mf.GetCurrentDirectory(),
- mf.GetSourceExtensions(),
- mf.GetHeaderExtensions(), this->Name.c_str());
- this->SourceFiles.push_back(mf.AddSource(file));
- }
+//----------------------------------------------------------------------------
+void cmTarget::TraceDependencies(const char* vsProjectFile)
+{
+ // Use a helper object to trace the dependencies.
+ cmTargetTraceDependencies tracer(this, vsProjectFile);
+ tracer.Trace();
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::AddSources(std::vector<std::string> const& srcs)
+{
+ for(std::vector<std::string>::const_iterator i = srcs.begin();
+ i != srcs.end(); ++i)
+ {
+ this->AddSource(i->c_str());
}
}
+cmSourceFile* cmTarget::AddSource(const char* s)
+{
+ std::string src = s;
+
+ // For backwards compatibility replace varibles in source names.
+ // This should eventually be removed.
+ this->Makefile->ExpandVariablesInString(src);
+
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(src.c_str());
+ this->AddSourceFile(sf);
+ return sf;
+}
+
void cmTarget::MergeLinkLibraries( cmMakefile& mf,
const char *selfname,
const LinkLibraryVectorType& libs )
@@ -1328,9 +1311,7 @@ void cmTarget::ComputeObjectFiles()
{
return;
}
-
- // Force the SourceFiles vector to be populated
- this->GenerateSourceFilesFromSourceLists(*this->Makefile);
+#if 0
std::vector<std::string> dirs;
this->Makefile->GetLocalGenerator()->
GetTargetObjectFileDirectories(this,
@@ -1346,10 +1327,7 @@ void cmTarget::ComputeObjectFiles()
s != this->SourceFiles.end(); ++s)
{
cmSourceFile* sf = *s;
- const char* lang = this->Makefile->GetLocalGenerator()->
- GetGlobalGenerator()->
- GetLanguageFromExtension(sf->GetSourceExtension().c_str());
- if (lang)
+ if(const char* lang = sf->GetLanguage())
{
std::string lookupObj = objExtensionLookup1 + lang;
lookupObj += objExtensionLookup2;
@@ -1371,6 +1349,7 @@ void cmTarget::ComputeObjectFiles()
}
}
this->SetProperty("OBJECT_FILES", objectFiles.c_str());
+#endif
}
@@ -1487,9 +1466,7 @@ const char* cmTarget::GetLinkerLanguage(cmGlobalGenerator* gg)
= this->SourceFiles.begin();
i != this->SourceFiles.end(); ++i)
{
- const char* lang =
- gg->GetLanguageFromExtension((*i)->GetSourceExtension().c_str());
- if(lang)
+ if(const char* lang = (*i)->GetLanguage())
{
languages.insert(lang);
}