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;