From 7c67524dfac73bc5b8dea586bab0ce3e8206aeb7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 8 Jul 2009 12:04:48 -0400 Subject: [PATCH] ENH: Introduce cmTarget::LinkImplementation API The new method centralizes loops that process raw OriginalLinkLibraries to extract the link implementation (libraries linked into the target) for each configuration. Results are computed on demand and then cached. This simplifies link interface computation because the default case trivially copies the link implementation. --- Source/cmComputeLinkDepends.cxx | 21 ++-- Source/cmTarget.cxx | 173 +++++++++++++++++++------------- Source/cmTarget.h | 16 +++ 3 files changed, 124 insertions(+), 86 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index ef6926a88..50a63ebd9 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -520,22 +520,15 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index, void cmComputeLinkDepends::AddDirectLinkEntries() { // Add direct link dependencies in this configuration. - int depender_index = -1; - LinkLibraryVectorType const& libs=this->Target->GetOriginalLinkLibraries(); - std::vector actual_libs; - for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin(); - li != libs.end(); ++li) + cmTarget::LinkImplementation const* impl = + this->Target->GetLinkImplementation(this->Config); + this->AddLinkEntries(-1, impl->Libraries); + for(std::vector::const_iterator + wi = impl->WrongConfigLibraries.begin(); + wi != impl->WrongConfigLibraries.end(); ++wi) { - if(li->second == cmTarget::GENERAL || li->second == this->LinkType) - { - actual_libs.push_back(li->first); - } - else if(this->OldLinkDirMode) - { - this->CheckWrongConfigItem(depender_index, li->first); - } + this->CheckWrongConfigItem(-1, *wi); } - this->AddLinkEntries(depender_index, actual_libs); } //---------------------------------------------------------------------------- diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 50a6ea9c4..c7fd6b0c0 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -81,6 +81,10 @@ public: typedef std::map ImportInfoMapType; ImportInfoMapType ImportInfoMap; + + // Cache link implementation computation from each configuration. + typedef std::map LinkImplMapType; + LinkImplMapType LinkImplMap; }; //---------------------------------------------------------------------------- @@ -3777,91 +3781,116 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) return false; } - // Is the link interface just the link implementation? - bool doLibraries = !explicitLibraries; - - // Do we need to construct a list of shared library dependencies not - // included in the interface? - bool doSharedDeps = (explicitLibraries && - this->GetType() == cmTarget::SHARED_LIBRARY); - - // Keep track of what libraries have been emitted. - std::set emitted; - std::set emittedWrongConfig; - if(explicitLibraries) { // The interface libraries have been explicitly set. cmSystemTools::ExpandListArgument(explicitLibraries, iface.Libraries); - for(std::vector::const_iterator - li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) + + if(this->GetType() == cmTarget::SHARED_LIBRARY) { - emitted.insert(*li); + // Shared libraries may have runtime implementation dependencies + // on other shared libraries that are not in the interface. + std::set emitted; + for(std::vector::const_iterator + li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) + { + emitted.insert(*li); + } + LinkImplementation const* impl = this->GetLinkImplementation(config); + for(std::vector::const_iterator + li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) + { + if(emitted.insert(*li).second) + { + if(cmTarget* tgt = this->Makefile->FindTargetToUse(li->c_str())) + { + // This is a runtime dependency on another shared library. + if(tgt->GetType() == cmTarget::SHARED_LIBRARY) + { + iface.SharedDeps.push_back(*li); + } + } + else + { + // TODO: Recognize shared library file names. Perhaps this + // should be moved to cmComputeLinkInformation, but that creates + // a chicken-and-egg problem since this list is needed for its + // construction. + } + } + } } } - - if(doLibraries || doSharedDeps) + else { - // Compute which library configuration to link. - cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config); - - // Construct the list of libs linked for this configuration. - cmTarget::LinkLibraryVectorType const& llibs = - this->GetOriginalLinkLibraries(); - for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin(); - li != llibs.end(); ++li) - { - // Skip entries that resolve to the target itself or are empty. - std::string item = this->CheckCMP0004(li->first); - if(item == this->GetName() || item.empty()) - { - continue; - } - - // Skip entries not meant for this configuration. - if(li->second != cmTarget::GENERAL && li->second != linkType) - { - // Support OLD behavior for CMP0003. - if(doLibraries && emittedWrongConfig.insert(item).second) - { - iface.WrongConfigLibraries.push_back(item); - } - continue; - } - - // Skip entries that have already been emitted. - if(!emitted.insert(item).second) - { - continue; - } - - // Emit this item. - if(doLibraries) - { - // This implementation dependency goes in the implicit interface. - iface.Libraries.push_back(item); - } - else if(cmTarget* tgt = this->Makefile->FindTargetToUse(item.c_str())) - { - // This is a runtime dependency on another shared library. - if(tgt->GetType() == cmTarget::SHARED_LIBRARY) - { - iface.SharedDeps.push_back(item); - } - } - else - { - // TODO: Recognize shared library file names. Perhaps this - // should be moved to cmComputeLinkInformation, but that creates - // a chicken-and-egg problem since this list is needed for its - // construction. - } - } + // The link implementation is the default link interface. + LinkImplementation const* impl = this->GetLinkImplementation(config); + iface.Libraries = impl->Libraries; + iface.WrongConfigLibraries = impl->WrongConfigLibraries; } return true; } +//---------------------------------------------------------------------------- +cmTarget::LinkImplementation const* +cmTarget::GetLinkImplementation(const char* config) +{ + // There is no link implementation for imported targets. + if(this->IsImported()) + { + return 0; + } + + // Lookup any existing link implementation for this configuration. + std::string key = cmSystemTools::UpperCase(config? config : ""); + cmTargetInternals::LinkImplMapType::iterator + i = this->Internal->LinkImplMap.find(key); + if(i == this->Internal->LinkImplMap.end()) + { + // Compute the link implementation for this configuration. + LinkImplementation impl; + this->ComputeLinkImplementation(config, impl); + + // Store the information for this configuration. + cmTargetInternals::LinkImplMapType::value_type entry(key, impl); + i = this->Internal->LinkImplMap.insert(entry).first; + } + + return &i->second; +} + +//---------------------------------------------------------------------------- +void cmTarget::ComputeLinkImplementation(const char* config, + LinkImplementation& impl) +{ + // Compute which library configuration to link. + cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config); + + LinkLibraryVectorType const& llibs = this->GetOriginalLinkLibraries(); + for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin(); + li != llibs.end(); ++li) + { + // Skip entries that resolve to the target itself or are empty. + std::string item = this->CheckCMP0004(li->first); + if(item == this->GetName() || item.empty()) + { + continue; + } + + if(li->second == cmTarget::GENERAL || li->second == linkType) + { + // The entry is meant for this configuration. + impl.Libraries.push_back(item); + } + else + { + // Support OLD behavior for CMP0003. + impl.WrongConfigLibraries.push_back(item); + } + } +} + //---------------------------------------------------------------------------- std::string cmTarget::CheckCMP0004(std::string const& item) { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index ad7e6110d..46c268e91 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -255,6 +255,19 @@ public: if the target cannot be linked. */ LinkInterface const* GetLinkInterface(const char* config); + /** The link implementation specifies the direct library + dependencies needed by the object files of the target. */ + struct LinkImplementation + { + // Libraries linked directly in this configuration. + std::vector Libraries; + + // Libraries linked directly in other configurations. + // Needed only for OLD behavior of CMP0003. + std::vector WrongConfigLibraries; + }; + LinkImplementation const* GetLinkImplementation(const char* config); + /** Strip off leading and trailing whitespace from an item named in the link dependencies of this target. */ std::string CheckCMP0004(std::string const& item); @@ -520,6 +533,9 @@ private: bool ComputeLinkInterface(const char* config, LinkInterface& iface); + void ComputeLinkImplementation(const char* config, + LinkImplementation& impl); + // The cmMakefile instance that owns this target. This should // always be set. cmMakefile* Makefile;