diff options
Diffstat (limited to 'Source/cmTarget.cxx')
-rw-r--r-- | Source/cmTarget.cxx | 471 |
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); } |