summaryrefslogtreecommitdiffstats
path: root/Source/cmTarget.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2007-06-18 15:59:23 (GMT)
committerBrad King <brad.king@kitware.com>2007-06-18 15:59:23 (GMT)
commit35936433e11728397dcdb2beab615674bfa79ec7 (patch)
tree8222a4daea955055c852d6db058421a570a8f6b2 /Source/cmTarget.cxx
parentef81ac50e5d6e981088c00e822fde538d9da9e37 (diff)
downloadCMake-35936433e11728397dcdb2beab615674bfa79ec7.zip
CMake-35936433e11728397dcdb2beab615674bfa79ec7.tar.gz
CMake-35936433e11728397dcdb2beab615674bfa79ec7.tar.bz2
ENH: Merging changes from branch CMake-SourceFile2-b between tags
CMake-SourceFile2-bp and CMake-SourceFile2-b-mp1 to trunk. This commit is surrounded by tags CMake-SourceFile2-b-mp1-pre and CMake-SourceFile2-b-mp1-post on the trunk. The changes re-implement cmSourceFile and the use of it to allow instances to be created much earlier. The use of cmSourceFileLocation allows locating a source file referenced by a user to be much simpler and more robust. The two SetName methods are no longer needed so some duplicate code has been removed. The strange "SourceName" stuff is gone. Code that created cmSourceFile instances on the stack and then sent them to cmMakefile::AddSource has been simplified and converted to getting cmSourceFile instances from cmMakefile. The CPluginAPI has preserved the old API through a compatibility interface. Source lists are gone. Targets now get real instances of cmSourceFile right away instead of storing a list of strings until the final pass. TraceVSDependencies has been re-written to avoid the use of SourceName. It is now called TraceDependencies since it is not just for VS. It is now implemented with a helper object which makes the code simpler.
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);
}