diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 995f191bd..6170e92e9 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -172,12 +172,10 @@ satisfy dependencies. //---------------------------------------------------------------------------- cmComputeLinkDepends -::cmComputeLinkDepends(cmTarget const* target, const std::string& config, - cmTarget const* head) +::cmComputeLinkDepends(cmTarget const* target, const std::string& config) { // Store context information. this->Target = target; - this->HeadTarget = head; this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = this->Makefile->GetLocalGenerator(); this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); @@ -294,8 +292,7 @@ cmComputeLinkDepends::AllocateLinkEntry(std::string const& item) } //---------------------------------------------------------------------------- -int cmComputeLinkDepends::AddLinkEntry(int depender_index, - std::string const& item) +int cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item) { // Check if the item entry has already been added. std::map::iterator lei = this->LinkEntryIndex.find(item); @@ -312,7 +309,7 @@ int cmComputeLinkDepends::AddLinkEntry(int depender_index, int index = lei->second; LinkEntry& entry = this->EntryList[index]; entry.Item = item; - entry.Target = this->FindTargetToLink(depender_index, entry.Item); + entry.Target = item.Target; entry.IsFlag = (!entry.Target && item[0] == '-' && item[1] != 'l' && item.substr(0, 10) != "-framework"); @@ -356,7 +353,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe) { // Follow the target dependencies. if(cmTarget::LinkInterface const* iface = - entry.Target->GetLinkInterface(this->Config, this->HeadTarget)) + entry.Target->GetLinkInterface(this->Config, this->Target)) { const bool isIface = entry.Target->GetType() == cmTarget::INTERFACE_LIBRARY; @@ -372,11 +369,11 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe) this->FollowSharedDeps(depender_index, iface); // Support for CMP0003. - for(std::vector::const_iterator + for(std::vector::const_iterator oi = iface->WrongConfigLibraries.begin(); oi != iface->WrongConfigLibraries.end(); ++oi) { - this->CheckWrongConfigItem(depender_index, *oi); + this->CheckWrongConfigItem(*oi); } } } @@ -408,9 +405,9 @@ cmComputeLinkDepends void cmComputeLinkDepends ::QueueSharedDependencies(int depender_index, - std::vector const& deps) + std::vector const& deps) { - for(std::vector::const_iterator li = deps.begin(); + for(std::vector::const_iterator li = deps.begin(); li != deps.end(); ++li) { SharedDepEntry qe; @@ -434,8 +431,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) // Initialize the item entry. LinkEntry& entry = this->EntryList[lei->second]; entry.Item = dep.Item; - entry.Target = this->FindTargetToLink(dep.DependerIndex, - dep.Item); + entry.Target = dep.Item.Target; // This item was added specifically because it is a dependent // shared library. It may get special treatment @@ -455,7 +451,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) if(entry.Target) { if(cmTarget::LinkInterface const* iface = - entry.Target->GetLinkInterface(this->Config, this->HeadTarget)) + entry.Target->GetLinkInterface(this->Config, this->Target)) { // Follow public and private dependencies transitively. this->FollowSharedDeps(index, iface, true); @@ -474,7 +470,7 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index, cmSystemTools::ExpandListArgument(value, deplist); // Look for entries meant for this configuration. - std::vector actual_libs; + std::vector actual_libs; cmTarget::LinkLibraryType llt = cmTarget::GENERAL; bool haveLLT = false; for(std::vector::const_iterator di = deplist.begin(); @@ -522,11 +518,13 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index, // If the library is meant for this link type then use it. if(llt == cmTarget::GENERAL || llt == this->LinkType) { - actual_libs.push_back(*di); + cmLinkItem item(*di, this->FindTargetToLink(depender_index, *di)); + actual_libs.push_back(item); } else if(this->OldLinkDirMode) { - this->CheckWrongConfigItem(depender_index, *di); + cmLinkItem item(*di, this->FindTargetToLink(depender_index, *di)); + this->CheckWrongConfigItem(item); } // Reset the link type until another explicit type is given. @@ -544,38 +542,38 @@ void cmComputeLinkDepends::AddDirectLinkEntries() { // Add direct link dependencies in this configuration. cmTarget::LinkImplementation const* impl = - this->Target->GetLinkImplementation(this->Config, this->HeadTarget); + this->Target->GetLinkImplementation(this->Config); this->AddLinkEntries(-1, impl->Libraries); - for(std::vector::const_iterator + for(std::vector::const_iterator wi = impl->WrongConfigLibraries.begin(); wi != impl->WrongConfigLibraries.end(); ++wi) { - this->CheckWrongConfigItem(-1, *wi); + this->CheckWrongConfigItem(*wi); } } //---------------------------------------------------------------------------- void -cmComputeLinkDepends::AddLinkEntries(int depender_index, - std::vector const& libs) +cmComputeLinkDepends::AddLinkEntries( + int depender_index, std::vector const& libs) { // Track inferred dependency sets implied by this list. std::map dependSets; // Loop over the libraries linked directly by the depender. - for(std::vector::const_iterator li = libs.begin(); + for(std::vector::const_iterator li = libs.begin(); li != libs.end(); ++li) { // Skip entries that will resolve to the target getting linked or // are empty. - std::string item = this->Target->CheckCMP0004(*li); + cmLinkItem const& item = *li; if(item == this->Target->GetName() || item.empty()) { continue; } // Add a link entry for this item. - int dependee_index = this->AddLinkEntry(depender_index, item); + int dependee_index = this->AddLinkEntry(*li); // The dependee must come after the depender. if(depender_index >= 0) @@ -625,40 +623,15 @@ cmTarget const* cmComputeLinkDepends::FindTargetToLink(int depender_index, const std::string& name) { // Look for a target in the scope of the depender. - cmMakefile* mf = this->Makefile; + cmTarget const* from = this->Target; if(depender_index >= 0) { if(cmTarget const* depender = this->EntryList[depender_index].Target) { - mf = depender->GetMakefile(); + from = depender; } } - cmTarget const* tgt = mf->FindTargetToUse(name); - - // Skip targets that will not really be linked. This is probably a - // name conflict between an external library and an executable - // within the project. - if(tgt && tgt->GetType() == cmTarget::EXECUTABLE && - !tgt->IsExecutableWithExports()) - { - tgt = 0; - } - - if(tgt && tgt->GetType() == cmTarget::OBJECT_LIBRARY) - { - cmOStringStream e; - e << "Target \"" << this->Target->GetName() << "\" links to " - "OBJECT library \"" << tgt->GetName() << "\" but this is not " - "allowed. " - "One may link only to STATIC or SHARED libraries, or to executables " - "with the ENABLE_EXPORTS property set."; - this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(), - this->Target->GetBacktrace()); - tgt = 0; - } - - // Return the target found, if any. - return tgt; + return from->FindTargetToLink(name); } //---------------------------------------------------------------------------- @@ -955,7 +928,7 @@ int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl) if(cmTarget const* target = this->EntryList[*ni].Target) { if(cmTarget::LinkInterface const* iface = - target->GetLinkInterface(this->Config, this->HeadTarget)) + target->GetLinkInterface(this->Config, this->Target)) { if(iface->Multiplicity > count) { @@ -988,8 +961,7 @@ void cmComputeLinkDepends::DisplayFinalEntries() } //---------------------------------------------------------------------------- -void cmComputeLinkDepends::CheckWrongConfigItem(int depender_index, - std::string const& item) +void cmComputeLinkDepends::CheckWrongConfigItem(cmLinkItem const& item) { if(!this->OldLinkDirMode) { @@ -999,12 +971,8 @@ void cmComputeLinkDepends::CheckWrongConfigItem(int depender_index, // For CMake 2.4 bug-compatibility we need to consider the output // directories of targets linked in another configuration as link // directories. - if(cmTarget const* tgt - = this->FindTargetToLink(depender_index, item)) + if(item.Target && !item.Target->IsImported()) { - if(!tgt->IsImported()) - { - this->OldWrongConfigItems.insert(tgt); - } + this->OldWrongConfigItems.insert(item.Target); } } diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 13fc993fb..3207ecbf5 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -32,8 +32,7 @@ class cmake; class cmComputeLinkDepends { public: - cmComputeLinkDepends(cmTarget const* target, const std::string& config, - cmTarget const* head); + cmComputeLinkDepends(cmTarget const* target, const std::string& config); ~cmComputeLinkDepends(); // Basic information about each link item. @@ -60,7 +59,6 @@ private: // Context information. cmTarget const* Target; - cmTarget const* HeadTarget; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; cmGlobalGenerator const* GlobalGenerator; @@ -79,11 +77,11 @@ private: std::map::iterator AllocateLinkEntry(std::string const& item); - int AddLinkEntry(int depender_index, std::string const& item); + int AddLinkEntry(cmLinkItem const& item); void AddVarLinkEntries(int depender_index, const char* value); void AddDirectLinkEntries(); void AddLinkEntries(int depender_index, - std::vector const& libs); + std::vector const& libs); cmTarget const* FindTargetToLink(int depender_index, const std::string& name); @@ -105,7 +103,7 @@ private: // of the interface. struct SharedDepEntry { - std::string Item; + cmLinkItem Item; int DependerIndex; }; std::queue SharedDepQueue; @@ -114,7 +112,7 @@ private: cmTarget::LinkInterface const* iface, bool follow_interface = false); void QueueSharedDependencies(int depender_index, - std::vector const& deps); + std::vector const& deps); void HandleSharedDependency(SharedDepEntry const& dep); // Dependency inferral for each link item. @@ -165,7 +163,7 @@ private: // Compatibility help. bool OldLinkDirMode; - void CheckWrongConfigItem(int depender_index, std::string const& item); + void CheckWrongConfigItem(cmLinkItem const& item); std::set OldWrongConfigItems; }; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 0ce04a5d1..e1852a360 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -239,12 +239,10 @@ because this need be done only for shared libraries without soname-s. //---------------------------------------------------------------------------- cmComputeLinkInformation -::cmComputeLinkInformation(cmTarget const* target, const std::string& config, - cmTarget const* headTarget) +::cmComputeLinkInformation(cmTarget const* target, const std::string& config) { // Store context information. this->Target = target; - this->HeadTarget = headTarget; this->Makefile = this->Target->GetMakefile(); this->LocalGenerator = this->Makefile->GetLocalGenerator(); this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); @@ -267,7 +265,7 @@ cmComputeLinkInformation this->OrderDependentRPath = 0; // Get the language used for linking this target. - this->LinkLanguage = this->Target->GetLinkerLanguage(config, headTarget); + this->LinkLanguage = this->Target->GetLinkerLanguage(config); if(this->LinkLanguage.empty()) { // The Compute method will do nothing, so skip the rest of the @@ -505,8 +503,7 @@ bool cmComputeLinkInformation::Compute() } // Compute the ordered link line items. - cmComputeLinkDepends cld(this->Target, this->Config, - this->HeadTarget); + cmComputeLinkDepends cld(this->Target, this->Config); cld.SetOldLinkDirMode(this->OldLinkDirMode); cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute(); @@ -572,8 +569,7 @@ bool cmComputeLinkInformation::Compute() void cmComputeLinkInformation::AddImplicitLinkInfo() { // The link closure lists all languages whose implicit info is needed. - cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config, - this->HeadTarget); + cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config); for(std::vector::const_iterator li = lc->Languages.begin(); li != lc->Languages.end(); ++li) { @@ -1972,7 +1968,7 @@ void cmComputeLinkInformation::GetRPath(std::vector& runtimeDirs, // present. This is done even when skipping rpath support. { cmTarget::LinkClosure const* lc = - this->Target->GetLinkClosure(this->Config, this->HeadTarget); + this->Target->GetLinkClosure(this->Config); for(std::vector::const_iterator li = lc->Languages.begin(); li != lc->Languages.end(); ++li) { diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index e345fe259..e5d674abf 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -29,8 +29,7 @@ class cmOrderDirectories; class cmComputeLinkInformation { public: - cmComputeLinkInformation(cmTarget const* target, const std::string& config, - cmTarget const* headTarget); + cmComputeLinkInformation(cmTarget const* target, const std::string& config); ~cmComputeLinkInformation(); bool Compute(); @@ -75,7 +74,6 @@ private: // Context information. cmTarget const* Target; - cmTarget const* HeadTarget; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; cmGlobalGenerator* GlobalGenerator; diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index f28217fc5..3929af40d 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -249,20 +249,21 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) const_cast(depender)->AddUtility(objLib); } } - std::vector tlibs; - depender->GetDirectLinkLibraries(*it, tlibs, depender); + + cmTarget::LinkImplementation const* impl = + depender->GetLinkImplementation(*it); // A target should not depend on itself. emitted.insert(depender->GetName()); - for(std::vector::const_iterator lib = tlibs.begin(); - lib != tlibs.end(); ++lib) + for(std::vector::const_iterator + lib = impl->Libraries.begin(); + lib != impl->Libraries.end(); ++lib) { // Don't emit the same library twice for this target. if(emitted.insert(*lib).second) { this->AddTargetDepend(depender_index, *lib, true); - this->AddInterfaceDepends(depender_index, *lib, - true, emitted); + this->AddInterfaceDepends(depender_index, *lib, emitted); } } } @@ -270,11 +271,11 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) // Loop over all utility dependencies. { - std::set const& tutils = depender->GetUtilities(); + std::set const& tutils = depender->GetUtilityItems(); std::set emitted; // A target should not depend on itself. emitted.insert(depender->GetName()); - for(std::set::const_iterator util = tutils.begin(); + for(std::set::const_iterator util = tutils.begin(); util != tutils.end(); ++util) { // Don't emit the same utility twice for this target. @@ -296,7 +297,7 @@ void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, if(cmTarget::LinkInterface const* iface = dependee->GetLinkInterface(config, depender)) { - for(std::vector::const_iterator + for(std::vector::const_iterator lib = iface->Libraries.begin(); lib != iface->Libraries.end(); ++lib) { @@ -304,8 +305,7 @@ void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, if(emitted.insert(*lib).second) { this->AddTargetDepend(depender_index, *lib, true); - this->AddInterfaceDepends(depender_index, *lib, - true, emitted); + this->AddInterfaceDepends(depender_index, *lib, emitted); } } } @@ -313,17 +313,15 @@ void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, //---------------------------------------------------------------------------- void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, - const std::string& dependee_name, - bool linking, + cmLinkItem const& dependee_name, std::set &emitted) { cmTarget const* depender = this->Targets[depender_index]; - cmTarget const* dependee = - depender->GetMakefile()->FindTargetToUse(dependee_name); + cmTarget const* dependee = dependee_name.Target; // Skip targets that will not really be linked. This is probably a // name conflict between an external library and an executable // within the project. - if(linking && dependee && + if(dependee && dependee->GetType() == cmTarget::EXECUTABLE && !dependee->IsExecutableWithExports()) { @@ -347,16 +345,15 @@ void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, } //---------------------------------------------------------------------------- -void cmComputeTargetDepends::AddTargetDepend(int depender_index, - const std::string& dependee_name, - bool linking) +void cmComputeTargetDepends::AddTargetDepend( + int depender_index, cmLinkItem const& dependee_name, + bool linking) { // Get the depender. cmTarget const* depender = this->Targets[depender_index]; // Check the target's makefile first. - cmTarget const* dependee = - depender->GetMakefile()->FindTargetToUse(dependee_name); + cmTarget const* dependee = dependee_name.Target; if(!dependee && !linking && (depender->GetType() != cmTarget::GLOBAL_TARGET)) @@ -424,12 +421,11 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index, if(dependee->IsImported()) { // Skip imported targets but follow their utility dependencies. - std::set const& utils = dependee->GetUtilities(); - for(std::set::const_iterator i = utils.begin(); + std::set const& utils = dependee->GetUtilityItems(); + for(std::set::const_iterator i = utils.begin(); i != utils.end(); ++i) { - if(cmTarget const* transitive_dependee = - dependee->GetMakefile()->FindTargetToUse(*i)) + if(cmTarget const* transitive_dependee = i->Target) { this->AddTargetDepend(depender_index, transitive_dependee, false); } diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index 755381635..902f342bf 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -20,6 +20,7 @@ class cmComputeComponentGraph; class cmGlobalGenerator; +class cmLinkItem; class cmTarget; class cmTargetDependSet; @@ -46,14 +47,14 @@ private: void CollectDepends(); void CollectTargetDepends(int depender_index); void AddTargetDepend(int depender_index, - const std::string& dependee_name, + cmLinkItem const& dependee_name, bool linking); void AddTargetDepend(int depender_index, cmTarget const* dependee, bool linking); bool ComputeFinalDepends(cmComputeComponentGraph const& ccg); void AddInterfaceDepends(int depender_index, - const std::string& dependee_name, - bool linking, std::set &emitted); + cmLinkItem const& dependee_name, + std::set &emitted); void AddInterfaceDepends(int depender_index, cmTarget const* dependee, const std::string& config, std::set &emitted); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 9f5eee56f..1f39d7af9 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -865,15 +865,16 @@ cmExportFileGenerator } //---------------------------------------------------------------------------- +template void cmExportFileGenerator ::SetImportLinkProperty(std::string const& suffix, cmTarget* target, const std::string& propName, - std::vector const& entries, + std::vector const& entries, ImportPropertyMap& properties, std::vector& missingTargets - ) + ) { // Skip the property if there are no entries. if(entries.empty()) @@ -884,7 +885,7 @@ cmExportFileGenerator // Construct the property value. std::string link_entries; const char* sep = ""; - for(std::vector::const_iterator li = entries.begin(); + for(typename std::vector::const_iterator li = entries.begin(); li != entries.end(); ++li) { // Separate this from the previous entry. @@ -902,7 +903,6 @@ cmExportFileGenerator properties[prop] = link_entries; } - //---------------------------------------------------------------------------- void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os, const std::string& config) diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index abd8ad531..919924e0e 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -95,9 +95,11 @@ protected: std::string const& suffix, cmTarget* target, ImportPropertyMap& properties, std::vector& missingTargets); + + template void SetImportLinkProperty(std::string const& suffix, cmTarget* target, const std::string& propName, - std::vector const& entries, + std::vector const& entries, ImportPropertyMap& properties, std::vector& missingTargets); diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 7dcb335d6..c925869b9 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -799,7 +799,8 @@ static const char* targetPropertyTransitiveWhitelist[] = { #undef TRANSITIVE_PROPERTY_NAME -std::string getLinkedTargetsContent(const std::vector &targets, +std::string getLinkedTargetsContent( + std::vector &targets, cmTarget const* target, cmTarget const* headTarget, cmGeneratorExpressionContext *context, @@ -810,7 +811,7 @@ std::string getLinkedTargetsContent(const std::vector &targets, std::string sep; std::string depString; - for (std::vector::const_iterator + for (std::vector::const_iterator it = targets.begin(); it != targets.end(); ++it) { @@ -827,7 +828,7 @@ std::string getLinkedTargetsContent(const std::vector &targets, sep = ";"; } cmsys::auto_ptr cge = ge.Parse(depString); - std::string linkedTargetsContent = cge->Evaluate(context->Makefile, + std::string linkedTargetsContent = cge->Evaluate(target->GetMakefile(), context->Config, context->Quiet, headTarget, @@ -840,21 +841,21 @@ std::string getLinkedTargetsContent(const std::vector &targets, return linkedTargetsContent; } -std::string getLinkedTargetsContent(const std::vector &libraries, +std::string getLinkedTargetsContent(std::vector const &libraries, cmTarget const* target, cmTarget const* headTarget, cmGeneratorExpressionContext *context, cmGeneratorExpressionDAGChecker *dagChecker, const std::string &interfacePropertyName) { - std::vector tgts; - for (std::vector::const_iterator + std::vector tgts; + for (std::vector::const_iterator it = libraries.begin(); it != libraries.end(); ++it) { - if (cmTarget *tgt = context->Makefile->FindTargetToUse(*it)) + if (it->Target) { - tgts.push_back(tgt); + tgts.push_back(it->Target); } } return getLinkedTargetsContent(tgts, target, headTarget, context, @@ -1082,7 +1083,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode cmStrCmp(propertyName)) != transEnd) { - std::vector tgts; + std::vector tgts; target->GetTransitivePropertyTargets(context->Config, headTarget, tgts); if (!tgts.empty()) @@ -1098,8 +1099,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode cmStrCmp(interfacePropertyName)) != transEnd) { const cmTarget::LinkImplementation *impl - = target->GetLinkImplementationLibraries(context->Config, - headTarget); + = target->GetLinkImplementationLibraries(context->Config); if(impl) { linkedTargetsContent = diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index a7576ed60..fd82d1742 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -252,7 +252,7 @@ cmGeneratorTarget::GetSourceDepends(cmSourceFile const* sf) const return 0; } -static void handleSystemIncludesDep(cmMakefile *mf, cmTarget* depTgt, +static void handleSystemIncludesDep(cmMakefile *mf, cmTarget const* depTgt, const std::string& config, cmTarget *headTarget, cmGeneratorExpressionDAGChecker *dagChecker, @@ -449,7 +449,7 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const std::string& dir, if (iter == this->SystemIncludesCache.end()) { cmTarget::LinkImplementation const* impl - = this->Target->GetLinkImplementation(config, this->Target); + = this->Target->GetLinkImplementation(config); if(!impl) { return false; @@ -474,11 +474,11 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const std::string& dir, &dagChecker), result); } - std::set uniqueDeps; - for(std::vector::const_iterator li = impl->Libraries.begin(); + std::set uniqueDeps; + for(std::vector::const_iterator li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) { - cmTarget* tgt = this->Makefile->FindTargetToUse(*li); + cmTarget const* tgt = li->Target; if (!tgt) { continue; @@ -489,10 +489,10 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const std::string& dir, handleSystemIncludesDep(this->Makefile, tgt, config, this->Target, &dagChecker, result, excludeImported); - std::vector deps; + std::vector deps; tgt->GetTransitivePropertyTargets(config, this->Target, deps); - for(std::vector::const_iterator di = deps.begin(); + for(std::vector::const_iterator di = deps.begin(); di != deps.end(); ++di) { if (uniqueDeps.insert(*di).second) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 29a5955a6..9a36df5aa 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1255,7 +1255,7 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget) // If the language is compiled as a source trust Xcode to link with it. cmTarget::LinkImplementation const* impl = - cmtarget.GetLinkImplementation("NOCONFIG", &cmtarget); + cmtarget.GetLinkImplementation("NOCONFIG"); for(std::vector::const_iterator li = impl->Languages.begin(); li != impl->Languages.end(); ++li) { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 01edde900..71d03df14 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -64,11 +64,16 @@ struct cmTarget::OutputInfo //---------------------------------------------------------------------------- struct cmTarget::ImportInfo { + ImportInfo(): NoSOName(false), Multiplicity(0) {} bool NoSOName; + int Multiplicity; std::string Location; std::string SOName; std::string ImportLibrary; - cmTarget::LinkInterface LinkInterface; + std::string Languages; + std::string Libraries; + std::string LibrariesProp; + std::string SharedDeps; }; //---------------------------------------------------------------------------- @@ -90,11 +95,13 @@ public: : Backtrace(NULL) { this->PolicyWarnedCMP0022 = false; + this->UtilityItemsDone = false; } cmTargetInternals(cmTargetInternals const&) : Backtrace(NULL) { this->PolicyWarnedCMP0022 = false; + this->UtilityItemsDone = false; } ~cmTargetInternals(); @@ -121,11 +128,14 @@ public: LinkInterfaceMapType LinkInterfaceMap; bool PolicyWarnedCMP0022; + typedef std::map + ImportLinkInterfaceMapType; + ImportLinkInterfaceMapType ImportLinkInterfaceMap; + typedef std::map OutputInfoMapType; OutputInfoMapType OutputInfoMap; - typedef std::map - ImportInfoMapType; + typedef std::map ImportInfoMapType; ImportInfoMapType ImportInfoMap; typedef std::map CompileInfoMapType; @@ -136,14 +146,16 @@ public: cmTarget::LinkImplementation> LinkImplMapType; LinkImplMapType LinkImplMap; - typedef std::map - LinkClosureMapType; + typedef std::map LinkClosureMapType; LinkClosureMapType LinkClosureMap; typedef std::map > SourceFilesMapType; SourceFilesMapType SourceFilesMap; + std::set UtilityItems; + bool UtilityItemsDone; + struct TargetPropertyEntry { TargetPropertyEntry(cmsys::auto_ptr cge, const std::string &targetName = std::string()) @@ -170,12 +182,15 @@ public: CachedLinkInterfaceSourcesEntries; mutable std::map > CachedLinkInterfaceCompileFeaturesEntries; + mutable std::map > + CachedLinkImplementationClosure; mutable std::map CacheLinkInterfaceIncludeDirectoriesDone; mutable std::map CacheLinkInterfaceCompileDefinitionsDone; mutable std::map CacheLinkInterfaceCompileOptionsDone; mutable std::map CacheLinkInterfaceSourcesDone; mutable std::map CacheLinkInterfaceCompileFeaturesDone; + mutable std::map CacheLinkImplementationClosureDone; }; //---------------------------------------------------------------------------- @@ -460,6 +475,22 @@ cmListFileBacktrace const* cmTarget::GetUtilityBacktrace( return &i->second; } +//---------------------------------------------------------------------------- +std::set const& cmTarget::GetUtilityItems() const +{ + if(!this->Internal->UtilityItemsDone) + { + this->Internal->UtilityItemsDone = true; + for(std::set::const_iterator i = this->Utilities.begin(); + i != this->Utilities.end(); ++i) + { + this->Internal->UtilityItems.insert( + cmLinkItem(*i, this->Makefile->FindTargetToUse(*i))); + } + } + return this->Internal->UtilityItems; +} + //---------------------------------------------------------------------------- void cmTarget::FinishConfigure() { @@ -479,6 +510,7 @@ void cmTarget::ClearLinkMaps() this->LinkImplementationLanguageIsContextDependent = true; this->Internal->LinkImplMap.clear(); this->Internal->LinkInterfaceMap.clear(); + this->Internal->ImportLinkInterfaceMap.clear(); this->Internal->LinkClosureMap.clear(); for (cmTargetLinkInformationMap::const_iterator it = this->LinkInformation.begin(); @@ -1194,63 +1226,6 @@ bool cmTarget::NameResolvesToFramework(const std::string& libname) const NameResolvesToFramework(libname); } -//---------------------------------------------------------------------------- -void cmTarget::GetDirectLinkLibraries(const std::string& config, - std::vector &libs, - cmTarget const* head) const -{ - const char *prop = this->GetProperty("LINK_LIBRARIES"); - if (prop) - { - cmGeneratorExpression ge; - const cmsys::auto_ptr cge = ge.Parse(prop); - - cmGeneratorExpressionDAGChecker dagChecker( - this->GetName(), - "LINK_LIBRARIES", 0, 0); - cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile, - config, - false, - head, - &dagChecker), - libs); - - std::set const& seenProps = cge->GetSeenTargetProperties(); - for (std::set::const_iterator it = seenProps.begin(); - it != seenProps.end(); ++it) - { - if (!this->GetProperty(*it)) - { - this->LinkImplicitNullProperties.insert(*it); - } - } - cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards); - } -} - -//---------------------------------------------------------------------------- -void cmTarget::GetInterfaceLinkLibraries(const std::string& config, - std::vector &libs, - cmTarget const* head) const -{ - const char *prop = this->GetProperty("INTERFACE_LINK_LIBRARIES"); - if (prop) - { - cmGeneratorExpression ge; - const cmsys::auto_ptr cge = ge.Parse(prop); - - cmGeneratorExpressionDAGChecker dagChecker( - this->GetName(), - "INTERFACE_LINK_LIBRARIES", 0, 0); - cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile, - config, - false, - head, - &dagChecker), - libs); - } -} - //---------------------------------------------------------------------------- std::string cmTarget::GetDebugGeneratorExpressions(const std::string &value, cmTarget::LinkLibraryType llt) const @@ -2294,9 +2269,8 @@ cmTarget::GetIncludeDirectories(const std::string& config) const if(this->Makefile->IsOn("APPLE")) { - LinkImplementation const* impl = this->GetLinkImplementation(config, - this); - for(std::vector::const_iterator + LinkImplementation const* impl = this->GetLinkImplementation(config); + for(std::vector::const_iterator it = impl->Libraries.begin(); it != impl->Libraries.end(); ++it) { @@ -3498,13 +3472,11 @@ public: Makefile(target->GetMakefile()), Target(target) { this->Visited.insert(target); } - void Visit(const std::string& name) + void Visit(cmLinkItem const& item) { - cmTarget *target = this->Makefile->FindTargetToUse(name); - - if(!target) + if(!item.Target) { - if(name.find("::") != std::string::npos) + if(item.find("::") != std::string::npos) { bool noMessage = false; cmake::MessageType messageType = cmake::FATAL_ERROR; @@ -3530,7 +3502,7 @@ public: if(!noMessage) { e << "Target \"" << this->Target->GetName() - << "\" links to target \"" << name + << "\" links to target \"" << item << "\" but the target was not found. Perhaps a find_package() " "call is missing for an IMPORTED target, or an ALIAS target is " "missing?"; @@ -3541,13 +3513,13 @@ public: } return; } - if(!this->Visited.insert(target).second) + if(!this->Visited.insert(item.Target).second) { return; } cmTarget::LinkInterface const* iface = - target->GetLinkInterface(this->Config, this->HeadTarget); + item.Target->GetLinkInterface(this->Config, this->HeadTarget); if(!iface) { return; } for(std::vector::const_iterator @@ -3556,7 +3528,7 @@ public: this->Languages.insert(*li); } - for(std::vector::const_iterator + for(std::vector::const_iterator li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li) { this->Visit(*li); @@ -3572,25 +3544,22 @@ private: }; //---------------------------------------------------------------------------- -std::string cmTarget::GetLinkerLanguage(const std::string& config, - cmTarget const* head) const +std::string cmTarget::GetLinkerLanguage(const std::string& config) const { - cmTarget const* headTarget = head ? head : this; - return this->GetLinkClosure(config, headTarget)->LinkerLanguage; + return this->GetLinkClosure(config)->LinkerLanguage; } //---------------------------------------------------------------------------- -cmTarget::LinkClosure const* cmTarget::GetLinkClosure( - const std::string& config, - cmTarget const* head) const +cmTarget::LinkClosure const* +cmTarget::GetLinkClosure(const std::string& config) const { - TargetConfigPair key(head, cmSystemTools::UpperCase(config)); + std::string key(cmSystemTools::UpperCase(config)); cmTargetInternals::LinkClosureMapType::iterator i = this->Internal->LinkClosureMap.find(key); if(i == this->Internal->LinkClosureMap.end()) { LinkClosure lc; - this->ComputeLinkClosure(config, lc, head); + this->ComputeLinkClosure(config, lc); cmTargetInternals::LinkClosureMapType::value_type entry(key, lc); i = this->Internal->LinkClosureMap.insert(entry).first; } @@ -3651,12 +3620,12 @@ public: }; //---------------------------------------------------------------------------- -void cmTarget::ComputeLinkClosure(const std::string& config, LinkClosure& lc, - cmTarget const* head) const +void cmTarget::ComputeLinkClosure(const std::string& config, + LinkClosure& lc) const { // Get languages built in this target. std::set languages; - LinkImplementation const* impl = this->GetLinkImplementation(config, head); + LinkImplementation const* impl = this->GetLinkImplementation(config); for(std::vector::const_iterator li = impl->Languages.begin(); li != impl->Languages.end(); ++li) { @@ -3664,8 +3633,8 @@ void cmTarget::ComputeLinkClosure(const std::string& config, LinkClosure& lc, } // Add interface languages from linked targets. - cmTargetCollectLinkLanguages cll(this, config, languages, head); - for(std::vector::const_iterator li = impl->Libraries.begin(); + cmTargetCollectLinkLanguages cll(this, config, languages, this); + for(std::vector::const_iterator li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) { cll.Visit(*li); @@ -3714,6 +3683,41 @@ void cmTarget::ComputeLinkClosure(const std::string& config, LinkClosure& lc, } } +//---------------------------------------------------------------------------- +void cmTarget::ExpandLinkItems(std::string const& prop, + std::string const& value, + std::string const& config, + cmTarget const* headTarget, + std::vector& items) const +{ + cmGeneratorExpression ge; + cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), prop, 0, 0); + std::vector libs; + cmSystemTools::ExpandListArgument(ge.Parse(value)->Evaluate( + this->Makefile, + config, + false, + headTarget, + this, &dagChecker), libs); + this->LookupLinkItems(libs, items); +} + +//---------------------------------------------------------------------------- +void cmTarget::LookupLinkItems(std::vector const& names, + std::vector& items) const +{ + for(std::vector::const_iterator i = names.begin(); + i != names.end(); ++i) + { + std::string name = this->CheckCMP0004(*i); + if(name == this->GetName() || name.empty()) + { + continue; + } + items.push_back(cmLinkItem(name, this->FindTargetToLink(name))); + } +} + //---------------------------------------------------------------------------- const char* cmTarget::GetSuffixVariableInternal(bool implib) const { @@ -3845,8 +3849,7 @@ bool cmTarget::HasSOName(const std::string& config) const return ((this->GetType() == cmTarget::SHARED_LIBRARY || this->GetType() == cmTarget::MODULE_LIBRARY) && !this->GetPropertyAsBool("NO_SONAME") && - this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config, - this))); + this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config))); } //---------------------------------------------------------------------------- @@ -3855,7 +3858,7 @@ std::string cmTarget::GetSOName(const std::string& config) const if(this->IsImported()) { // Lookup the imported soname. - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this)) + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) { if(info->NoSOName) { @@ -3923,7 +3926,7 @@ bool cmTarget::HasMacOSXRpathInstallNameDir(const std::string& config) const else { // Lookup the imported soname. - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this)) + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) { if(!info->NoSOName && !info->SOName.empty()) { @@ -4009,7 +4012,7 @@ bool cmTarget::IsImportedSharedLibWithoutSOName( { if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY) { - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this)) + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) { return info->NoSOName; } @@ -4133,7 +4136,7 @@ std::string cmTarget::ImportedGetFullPath(const std::string& config, bool implib) const { std::string result; - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this)) + if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) { result = implib? info->ImportLibrary : info->Location; } @@ -4219,7 +4222,7 @@ void cmTarget::GetFullNameInternal(const std::string& config, const char* suffixVar = this->GetSuffixVariableInternal(implib); // Check for language-specific default prefix and suffix. - std::string ll = this->GetLinkerLanguage(config, this); + std::string ll = this->GetLinkerLanguage(config); if(!ll.empty()) { if(!targetSuffix && suffixVar && *suffixVar) @@ -4507,9 +4510,12 @@ bool cmTarget::HaveBuildTreeRPATH(const std::string& config) const { return false; } - std::vector libs; - this->GetDirectLinkLibraries(config, libs, this); - return !libs.empty(); + if(LinkImplementation const* impl = + this->GetLinkImplementationLibraries(config)) + { + return !impl->Libraries.empty(); + } + return false; } //---------------------------------------------------------------------------- @@ -4558,7 +4564,7 @@ bool cmTarget::NeedRelinkBeforeInstall(const std::string& config) const } // Check for rpath support on this platform. - std::string ll = this->GetLinkerLanguage(config, this); + std::string ll = this->GetLinkerLanguage(config); if(!ll.empty()) { std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; @@ -5212,8 +5218,8 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet)); - std::vector deps; - tgt->GetTransitiveTargetClosure(config, tgt, deps); + std::vector const& deps = + tgt->GetLinkImplementationClosure(config); if(deps.empty()) { @@ -5238,7 +5244,7 @@ PropertyType checkInterfacePropertyCompatibility(cmTarget const* tgt, report += "\" property not set.\n"; } - for(std::vector::const_iterator li = + for(std::vector::const_iterator li = deps.begin(); li != deps.end(); ++li) { @@ -5428,16 +5434,15 @@ bool isLinkDependentProperty(cmTarget const* tgt, const std::string &p, const std::string& interfaceProperty, const std::string& config) { - std::vector deps; - tgt->GetTransitiveTargetClosure(config, tgt, deps); + std::vector const& deps = + tgt->GetLinkImplementationClosure(config); if(deps.empty()) { return false; } - for(std::vector::const_iterator li = - deps.begin(); + for(std::vector::const_iterator li = deps.begin(); li != deps.end(); ++li) { const char *prop = (*li)->GetProperty(interfaceProperty); @@ -5647,7 +5652,7 @@ bool cmTarget::IsChrpathUsed(const std::string& config) const #if defined(CMAKE_USE_ELF_PARSER) // Enable if the rpath flag uses a separator and the target uses ELF // binaries. - std::string ll = this->GetLinkerLanguage(config, this); + std::string ll = this->GetLinkerLanguage(config); if(!ll.empty()) { std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; @@ -5672,8 +5677,7 @@ bool cmTarget::IsChrpathUsed(const std::string& config) const //---------------------------------------------------------------------------- cmTarget::ImportInfo const* -cmTarget::GetImportInfo(const std::string& config, - cmTarget const* headTarget) const +cmTarget::GetImportInfo(const std::string& config) const { // There is no imported information for non-imported targets. if(!this->IsImported()) @@ -5692,16 +5696,15 @@ cmTarget::GetImportInfo(const std::string& config, { config_upper = "NOCONFIG"; } - TargetConfigPair key(headTarget, config_upper); typedef cmTargetInternals::ImportInfoMapType ImportInfoMapType; ImportInfoMapType::const_iterator i = - this->Internal->ImportInfoMap.find(key); + this->Internal->ImportInfoMap.find(config_upper); if(i == this->Internal->ImportInfoMap.end()) { ImportInfo info; - this->ComputeImportInfo(config_upper, info, headTarget); - ImportInfoMapType::value_type entry(key, info); + this->ComputeImportInfo(config_upper, info); + ImportInfoMapType::value_type entry(config_upper, info); i = this->Internal->ImportInfoMap.insert(entry).first; } @@ -5853,8 +5856,7 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, //---------------------------------------------------------------------------- void cmTarget::ComputeImportInfo(std::string const& desired_config, - ImportInfo& info, - cmTarget const* headTarget) const + ImportInfo& info) const { // This method finds information about an imported target from its // properties. The "IMPORTED_" namespace is reserved for properties @@ -5893,19 +5895,8 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, } if(propertyLibs) { - cmGeneratorExpression ge; - - cmGeneratorExpressionDAGChecker dagChecker( - this->GetName(), - linkProp, 0, 0); - cmSystemTools::ExpandListArgument(ge.Parse(propertyLibs) - ->Evaluate(this->Makefile, - desired_config, - false, - headTarget, - this, - &dagChecker), - info.LinkInterface.Libraries); + info.LibrariesProp = linkProp; + info.Libraries = propertyLibs; } } if(this->GetType() == INTERFACE_LIBRARY) @@ -5991,13 +5982,12 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, linkProp += suffix; if(const char* config_libs = this->GetProperty(linkProp)) { - cmSystemTools::ExpandListArgument(config_libs, - info.LinkInterface.SharedDeps); + info.SharedDeps = config_libs; } else if(const char* libs = this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) { - cmSystemTools::ExpandListArgument(libs, info.LinkInterface.SharedDeps); + info.SharedDeps = libs; } } @@ -6008,14 +5998,12 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, linkProp += suffix; if(const char* config_libs = this->GetProperty(linkProp)) { - cmSystemTools::ExpandListArgument(config_libs, - info.LinkInterface.Languages); + info.Languages = config_libs; } else if(const char* libs = this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) { - cmSystemTools::ExpandListArgument(libs, - info.LinkInterface.Languages); + info.Languages = libs; } } @@ -6026,12 +6014,12 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, linkProp += suffix; if(const char* config_reps = this->GetProperty(linkProp)) { - sscanf(config_reps, "%u", &info.LinkInterface.Multiplicity); + sscanf(config_reps, "%u", &info.Multiplicity); } else if(const char* reps = this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) { - sscanf(reps, "%u", &info.LinkInterface.Multiplicity); + sscanf(reps, "%u", &info.Multiplicity); } } } @@ -6044,11 +6032,7 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface( // Imported targets have their own link interface. if(this->IsImported()) { - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head)) - { - return &info->LinkInterface; - } - return 0; + return this->GetImportLinkInterface(config, head); } // Link interfaces are not supported for executables that do not @@ -6097,11 +6081,7 @@ cmTarget::GetLinkInterfaceLibraries(const std::string& config, // Imported targets have their own link interface. if(this->IsImported()) { - if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head)) - { - return &info->LinkInterface; - } - return 0; + return this->GetImportLinkInterface(config, head); } // Link interfaces are not supported for executables that do not @@ -6134,54 +6114,91 @@ cmTarget::GetLinkInterfaceLibraries(const std::string& config, return i->second.Exists ? &i->second : 0; } +//---------------------------------------------------------------------------- +cmTarget::LinkInterface const* +cmTarget::GetImportLinkInterface(const std::string& config, + cmTarget const* headTarget) const +{ + cmTarget::ImportInfo const* info = this->GetImportInfo(config); + if(!info) + { + return 0; + } + + TargetConfigPair key(headTarget, cmSystemTools::UpperCase(config)); + + cmTargetInternals::ImportLinkInterfaceMapType::iterator i = + this->Internal->ImportLinkInterfaceMap.find(key); + if(i == this->Internal->ImportLinkInterfaceMap.end()) + { + LinkInterface iface; + iface.Multiplicity = info->Multiplicity; + cmSystemTools::ExpandListArgument(info->Languages, iface.Languages); + this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config, + headTarget, iface.Libraries); + { + std::vector deps; + cmSystemTools::ExpandListArgument(info->SharedDeps, deps); + this->LookupLinkItems(deps, iface.SharedDeps); + } + + cmTargetInternals::ImportLinkInterfaceMapType::value_type + entry(key, iface); + i = this->Internal->ImportLinkInterfaceMap.insert(entry).first; + } + return &i->second; +} + //---------------------------------------------------------------------------- void processILibs(const std::string& config, cmTarget const* headTarget, - std::string const& name, - std::vector& tgts, std::set& emitted) + cmLinkItem const& item, + std::vector& tgts, + std::set& emitted) { - if (cmTarget* tgt = headTarget->GetMakefile() - ->FindTargetToUse(name)) + if (item.Target && emitted.insert(item.Target).second) { - if (emitted.insert(tgt).second) + tgts.push_back(item.Target); + if(cmTarget::LinkInterface const* iface = + item.Target->GetLinkInterfaceLibraries(config, headTarget)) { - tgts.push_back(tgt); - cmTarget::LinkInterface const* iface = - tgt->GetLinkInterfaceLibraries(config, headTarget); - if (iface) - { - for(std::vector::const_iterator + for(std::vector::const_iterator it = iface->Libraries.begin(); - it != iface->Libraries.end(); ++it) - { - processILibs(config, headTarget, *it, tgts, emitted); - } + it != iface->Libraries.end(); ++it) + { + processILibs(config, headTarget, *it, tgts, emitted); } } } } //---------------------------------------------------------------------------- -void cmTarget::GetTransitiveTargetClosure(const std::string& config, - cmTarget const* headTarget, - std::vector &tgts) const +std::vector const& +cmTarget::GetLinkImplementationClosure(const std::string& config) const { - std::set emitted; - - cmTarget::LinkImplementation const* impl - = this->GetLinkImplementationLibraries(config, headTarget); - - for(std::vector::const_iterator it = impl->Libraries.begin(); - it != impl->Libraries.end(); ++it) + std::vector& tgts = + this->Internal->CachedLinkImplementationClosure[config]; + if(!this->Internal->CacheLinkImplementationClosureDone[config]) { - processILibs(config, headTarget, *it, tgts, emitted); + this->Internal->CacheLinkImplementationClosureDone[config] = true; + std::set emitted; + + cmTarget::LinkImplementation const* impl + = this->GetLinkImplementationLibraries(config); + + for(std::vector::const_iterator it = impl->Libraries.begin(); + it != impl->Libraries.end(); ++it) + { + processILibs(config, this, *it, tgts , emitted); + } } + return tgts; } //---------------------------------------------------------------------------- void cmTarget::GetTransitivePropertyTargets(const std::string& config, cmTarget const* headTarget, - std::vector &tgts) const + std::vector &tgts) const { cmTarget::LinkInterface const* iface = this->GetLinkInterfaceLibraries(config, headTarget); @@ -6193,13 +6210,12 @@ void cmTarget::GetTransitivePropertyTargets(const std::string& config, || this->GetPolicyStatusCMP0022() == cmPolicies::WARN || this->GetPolicyStatusCMP0022() == cmPolicies::OLD) { - for(std::vector::const_iterator it = iface->Libraries.begin(); + for(std::vector::const_iterator it = iface->Libraries.begin(); it != iface->Libraries.end(); ++it) { - if (cmTarget* tgt = headTarget->GetMakefile() - ->FindTargetToUse(*it)) + if (it->Target) { - tgts.push_back(tgt); + tgts.push_back(it->Target); } } return; @@ -6229,8 +6245,7 @@ void cmTarget::GetTransitivePropertyTargets(const std::string& config, for(std::vector::const_iterator it = libs.begin(); it != libs.end(); ++it) { - if (cmTarget* tgt = headTarget->GetMakefile() - ->FindTargetToUse(*it)) + if (cmTarget const* tgt = this->FindTargetToLink(*it)) { tgts.push_back(tgt); } @@ -6325,15 +6340,8 @@ const char* cmTarget::ComputeLinkInterfaceLibraries(const std::string& config, if(explicitLibraries) { // The interface libraries have been explicitly set. - cmGeneratorExpression ge; - cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), - linkIfaceProp, 0, 0); - cmSystemTools::ExpandListArgument(ge.Parse(explicitLibraries)->Evaluate( - this->Makefile, - config, - false, - headTarget, - this, &dagChecker), iface.Libraries); + this->ExpandLinkItems(linkIfaceProp, explicitLibraries, config, + headTarget, iface.Libraries); } else if (this->PolicyStatusCMP0022 == cmPolicies::WARN || this->PolicyStatusCMP0022 == cmPolicies::OLD) @@ -6344,32 +6352,26 @@ const char* cmTarget::ComputeLinkInterfaceLibraries(const std::string& config, { // The link implementation is the default link interface. LinkImplementation const* impl = - this->GetLinkImplementationLibraries(config, headTarget); + this->GetLinkImplementationLibrariesInternal(config, headTarget); iface.Libraries = impl->Libraries; if(this->PolicyStatusCMP0022 == cmPolicies::WARN && !this->Internal->PolicyWarnedCMP0022) { // Compare the link implementation fallback link interface to the // preferred new link interface property and warn if different. - cmGeneratorExpression ge; - cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), - "INTERFACE_LINK_LIBRARIES", 0, 0); - std::vector ifaceLibs; - const char* newExplicitLibraries = - this->GetProperty("INTERFACE_LINK_LIBRARIES"); - cmSystemTools::ExpandListArgument( - ge.Parse(newExplicitLibraries)->Evaluate(this->Makefile, - config, - false, - headTarget, - this, &dagChecker), - ifaceLibs); + std::vector ifaceLibs; + std::string newProp = "INTERFACE_LINK_LIBRARIES"; + if(const char* newExplicitLibraries = this->GetProperty(newProp)) + { + this->ExpandLinkItems(newProp, newExplicitLibraries, config, + headTarget, ifaceLibs); + } if (ifaceLibs != impl->Libraries) { std::string oldLibraries; std::string newLibraries; const char *sep = ""; - for(std::vector::const_iterator it + for(std::vector::const_iterator it = impl->Libraries.begin(); it != impl->Libraries.end(); ++it) { oldLibraries += sep; @@ -6377,7 +6379,7 @@ const char* cmTarget::ComputeLinkInterfaceLibraries(const std::string& config, sep = ";"; } sep = ""; - for(std::vector::const_iterator it + for(std::vector::const_iterator it = ifaceLibs.begin(); it != ifaceLibs.end(); ++it) { newLibraries += sep; @@ -6428,7 +6430,7 @@ void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, // 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 + for(std::vector::const_iterator li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li) { emitted.insert(*li); @@ -6436,16 +6438,16 @@ void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, if (thisTarget->GetType() != cmTarget::INTERFACE_LIBRARY) { cmTarget::LinkImplementation const* impl = - thisTarget->GetLinkImplementation(config, headTarget); - for(std::vector::const_iterator + thisTarget->GetLinkImplementation(config); + for(std::vector::const_iterator li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) { if(emitted.insert(*li).second) { - if(cmTarget* tgt = thisTarget->Makefile->FindTargetToUse(*li)) + if(li->Target) { // This is a runtime dependency on another shared library. - if(tgt->GetType() == cmTarget::SHARED_LIBRARY) + if(li->Target->GetType() == cmTarget::SHARED_LIBRARY) { iface.SharedDeps.push_back(*li); } @@ -6467,7 +6469,8 @@ void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, { // The link implementation is the default link interface. cmTarget::LinkImplementation const* - impl = thisTarget->GetLinkImplementation(config, headTarget); + impl = thisTarget->GetLinkImplementationLibrariesInternal(config, + headTarget); iface.ImplementationIsInterface = true; iface.WrongConfigLibraries = impl->WrongConfigLibraries; } @@ -6476,7 +6479,7 @@ void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, { // Targets using this archive need its language runtime libraries. if(cmTarget::LinkImplementation const* impl = - thisTarget->GetLinkImplementation(config, headTarget)) + thisTarget->GetLinkImplementation(config)) { iface.Languages = impl->Languages; } @@ -6514,8 +6517,7 @@ void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget, //---------------------------------------------------------------------------- cmTarget::LinkImplementation const* -cmTarget::GetLinkImplementation(const std::string& config, - cmTarget const* head) const +cmTarget::GetLinkImplementation(const std::string& config) const { // There is no link implementation for imported targets. if(this->IsImported()) @@ -6524,7 +6526,7 @@ cmTarget::GetLinkImplementation(const std::string& config, } // Lookup any existing link implementation for this configuration. - TargetConfigPair key(head, cmSystemTools::UpperCase(config)); + TargetConfigPair key(this, cmSystemTools::UpperCase(config)); cmTargetInternals::LinkImplMapType::iterator i = this->Internal->LinkImplMap.find(key); @@ -6532,8 +6534,8 @@ cmTarget::GetLinkImplementation(const std::string& config, { // Compute the link implementation for this configuration. LinkImplementation impl; - this->ComputeLinkImplementation(config, impl, head); - this->ComputeLinkImplementationLanguages(config, impl, head); + this->ComputeLinkImplementation(config, impl, this); + this->ComputeLinkImplementationLanguages(config, impl, this); // Store the information for this configuration. cmTargetInternals::LinkImplMapType::value_type entry(key, impl); @@ -6541,7 +6543,7 @@ cmTarget::GetLinkImplementation(const std::string& config, } else if (i->second.Languages.empty()) { - this->ComputeLinkImplementationLanguages(config, i->second, head); + this->ComputeLinkImplementationLanguages(config, i->second, this); } return &i->second; @@ -6549,8 +6551,15 @@ cmTarget::GetLinkImplementation(const std::string& config, //---------------------------------------------------------------------------- cmTarget::LinkImplementation const* -cmTarget::GetLinkImplementationLibraries(const std::string& config, - cmTarget const* head) const +cmTarget::GetLinkImplementationLibraries(const std::string& config) const +{ + return this->GetLinkImplementationLibrariesInternal(config, this); +} + +//---------------------------------------------------------------------------- +cmTarget::LinkImplementation const* +cmTarget::GetLinkImplementationLibrariesInternal(const std::string& config, + cmTarget const* head) const { // There is no link implementation for imported targets. if(this->IsImported()) @@ -6584,15 +6593,41 @@ void cmTarget::ComputeLinkImplementation(const std::string& config, { // Collect libraries directly linked in this configuration. std::vector llibs; - this->GetDirectLinkLibraries(config, llibs, head); + if(const char *prop = this->GetProperty("LINK_LIBRARIES")) + { + cmGeneratorExpression ge; + const cmsys::auto_ptr cge = ge.Parse(prop); + + cmGeneratorExpressionDAGChecker dagChecker( + this->GetName(), + "LINK_LIBRARIES", 0, 0); + cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile, + config, + false, + head, + &dagChecker), + llibs); + + std::set const& seenProps = cge->GetSeenTargetProperties(); + for (std::set::const_iterator it = seenProps.begin(); + it != seenProps.end(); ++it) + { + if (!this->GetProperty(*it)) + { + this->LinkImplicitNullProperties.insert(*it); + } + } + cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards); + } + for(std::vector::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); - if(item == this->GetName() || item.empty()) + std::string name = this->CheckCMP0004(*li); + if(name == this->GetName() || name.empty()) { - if(item == this->GetName()) + if(name == this->GetName()) { bool noMessage = false; cmake::MessageType messageType = cmake::FATAL_ERROR; @@ -6631,7 +6666,8 @@ void cmTarget::ComputeLinkImplementation(const std::string& config, } // The entry is meant for this configuration. - impl.Libraries.push_back(item); + impl.Libraries.push_back( + cmLinkItem(name, this->FindTargetToLink(name))); } cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config); @@ -6641,13 +6677,14 @@ void cmTarget::ComputeLinkImplementation(const std::string& config, { if(li->second != cmTarget::GENERAL && li->second != linkType) { - std::string item = this->CheckCMP0004(li->first); - if(item == this->GetName() || item.empty()) + std::string name = this->CheckCMP0004(li->first); + if(name == this->GetName() || name.empty()) { continue; } // Support OLD behavior for CMP0003. - impl.WrongConfigLibraries.push_back(item); + impl.WrongConfigLibraries.push_back( + cmLinkItem(name, this->FindTargetToLink(name))); } } } @@ -6670,6 +6707,37 @@ cmTarget::ComputeLinkImplementationLanguages(const std::string& config, } } +//---------------------------------------------------------------------------- +cmTarget const* cmTarget::FindTargetToLink(std::string const& name) const +{ + cmTarget const* tgt = this->Makefile->FindTargetToUse(name); + + // Skip targets that will not really be linked. This is probably a + // name conflict between an external library and an executable + // within the project. + if(tgt && tgt->GetType() == cmTarget::EXECUTABLE && + !tgt->IsExecutableWithExports()) + { + tgt = 0; + } + + if(tgt && tgt->GetType() == cmTarget::OBJECT_LIBRARY) + { + cmOStringStream e; + e << "Target \"" << this->GetName() << "\" links to " + "OBJECT library \"" << tgt->GetName() << "\" but this is not " + "allowed. " + "One may link only to STATIC or SHARED libraries, or to executables " + "with the ENABLE_EXPORTS property set."; + cmake* cm = this->Makefile->GetCMakeInstance(); + cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace()); + tgt = 0; + } + + // Return the target found, if any. + return tgt; +} + //---------------------------------------------------------------------------- std::string cmTarget::CheckCMP0004(std::string const& item) const { @@ -6967,19 +7035,17 @@ void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info, //---------------------------------------------------------------------------- cmComputeLinkInformation* -cmTarget::GetLinkInformation(const std::string& config, - cmTarget const* head) const +cmTarget::GetLinkInformation(const std::string& config) const { - cmTarget const* headTarget = head ? head : this; // Lookup any existing information for this configuration. - TargetConfigPair key(headTarget, cmSystemTools::UpperCase(config)); + std::string key(cmSystemTools::UpperCase(config)); cmTargetLinkInformationMap::iterator i = this->LinkInformation.find(key); if(i == this->LinkInformation.end()) { // Compute information for this configuration. cmComputeLinkInformation* info = - new cmComputeLinkInformation(this, config, headTarget); + new cmComputeLinkInformation(this, config); if(!info || !info->Compute()) { delete info; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 2d51835e3..3f534f2db 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -43,12 +43,22 @@ class cmTarget; class cmGeneratorTarget; class cmTargetTraceDependencies; -struct cmTargetLinkInformationMap: - public std::map, - cmComputeLinkInformation*> +// Basic information about each link item. +class cmLinkItem: public std::string { - typedef std::map, - cmComputeLinkInformation*> derived; + typedef std::string std_string; +public: + cmLinkItem(): std_string(), Target(0) {} + cmLinkItem(const std_string& n, + cmTarget const* t): std_string(n), Target(t) {} + cmLinkItem(cmLinkItem const& r): std_string(r), Target(r.Target) {} + cmTarget const* Target; +}; + +struct cmTargetLinkInformationMap: + public std::map +{ + typedef std::map derived; cmTargetLinkInformationMap() {} cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r); ~cmTargetLinkInformationMap(); @@ -159,12 +169,6 @@ public: return this->LinkLibraries;} const LinkLibraryVectorType &GetOriginalLinkLibraries() const {return this->OriginalLinkLibraries;} - void GetDirectLinkLibraries(const std::string& config, - std::vector &, - cmTarget const* head) const; - void GetInterfaceLinkLibraries(const std::string& config, - std::vector &, - cmTarget const* head) const; /** Compute the link type to use for the given configuration. */ LinkLibraryType ComputeLinkType(const std::string& config) const; @@ -221,6 +225,7 @@ public: void AddUtility(const std::string& u, cmMakefile *makefile = 0); ///! Get the utilities used by this target std::setconst& GetUtilities() const { return this->Utilities; } + std::setconst& GetUtilityItems() const; cmListFileBacktrace const* GetUtilityBacktrace(const std::string& u) const; /** Finalize the target at the end of the Configure step. */ @@ -252,10 +257,10 @@ public: std::vector Languages; // Libraries listed in the interface. - std::vector Libraries; + std::vector Libraries; // Shared library dependencies needed for linking on some platforms. - std::vector SharedDeps; + std::vector SharedDeps; // Number of repetitions of a strongly connected component of two // or more static libraries. @@ -263,7 +268,7 @@ public: // Libraries listed for other configurations. // Needed only for OLD behavior of CMP0003. - std::vector WrongConfigLibraries; + std::vector WrongConfigLibraries; bool ImplementationIsInterface; @@ -277,11 +282,10 @@ public: LinkInterface const* GetLinkInterfaceLibraries(const std::string& config, cmTarget const* headTarget) const; void GetTransitivePropertyTargets(const std::string& config, - cmTarget const* headTarget, - std::vector &libs) const; - void GetTransitiveTargetClosure(const std::string& config, - cmTarget const* headTarget, - std::vector &libs) const; + cmTarget const* headTarget, + std::vector &libs) const; + std::vector const& + GetLinkImplementationClosure(const std::string& config) const; /** The link implementation specifies the direct library dependencies needed by the object files of the target. */ @@ -291,18 +295,17 @@ public: std::vector Languages; // Libraries linked directly in this configuration. - std::vector Libraries; + std::vector Libraries; // Libraries linked directly in other configurations. // Needed only for OLD behavior of CMP0003. - std::vector WrongConfigLibraries; + std::vector WrongConfigLibraries; }; - LinkImplementation const* GetLinkImplementation(const std::string& config, - cmTarget const* head) const; + LinkImplementation const* + GetLinkImplementation(const std::string& config) const; - LinkImplementation const* GetLinkImplementationLibraries( - const std::string& config, - cmTarget const* head) const; + LinkImplementation const* + GetLinkImplementationLibraries(const std::string& config) const; /** Link information from the transitive closure of the link implementation and the interfaces of its dependencies. */ @@ -314,8 +317,9 @@ public: // Languages whose runtime libraries must be linked. std::vector Languages; }; - LinkClosure const* GetLinkClosure(const std::string& config, - cmTarget const* head) const; + LinkClosure const* GetLinkClosure(const std::string& config) const; + + cmTarget const* FindTargetToLink(std::string const& name) const; /** Strip off leading and trailing whitespace from an item named in the link dependencies of this target. */ @@ -361,8 +365,7 @@ public: GetTargetVersion(bool soversion, int& major, int& minor, int& patch) const; ///! Return the preferred linker language for this target - std::string GetLinkerLanguage(const std::string& config = "", - cmTarget const* head = 0) const; + std::string GetLinkerLanguage(const std::string& config = "") const; /** Get the full name of the target according to the settings in its makefile. */ @@ -446,8 +449,8 @@ public: * install tree. For example: "\@rpath/" or "\@loader_path/". */ std::string GetInstallNameDirForInstallTree() const; - cmComputeLinkInformation* GetLinkInformation(const std::string& config, - cmTarget const* head = 0) const; + cmComputeLinkInformation* + GetLinkInformation(const std::string& config) const; // Get the properties cmPropertyMap &GetProperties() const { return this->Properties; } @@ -740,10 +743,9 @@ private: // Cache import information from properties for each configuration. struct ImportInfo; - ImportInfo const* GetImportInfo(const std::string& config, - cmTarget const* workingTarget) const; - void ComputeImportInfo(std::string const& desired_config, ImportInfo& info, - cmTarget const* head) const; + ImportInfo const* GetImportInfo(const std::string& config) const; + void ComputeImportInfo(std::string const& desired_config, + ImportInfo& info) const; // Cache target compile paths for each configuration. struct CompileInfo; @@ -753,19 +755,31 @@ private: void CheckPropertyCompatibility(cmComputeLinkInformation *info, const std::string& config) const; + LinkInterface const* + GetImportLinkInterface(const std::string& config, + cmTarget const* head) const; + const char* ComputeLinkInterfaceLibraries(const std::string& config, LinkInterface& iface, cmTarget const* head, bool &exists) const; + LinkImplementation const* + GetLinkImplementationLibrariesInternal(const std::string& config, + cmTarget const* head) const; void ComputeLinkImplementation(const std::string& config, LinkImplementation& impl, cmTarget const* head) const; void ComputeLinkImplementationLanguages(const std::string& config, LinkImplementation& impl, cmTarget const* head) const; - void ComputeLinkClosure(const std::string& config, LinkClosure& lc, - cmTarget const* head) const; + void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const; + + void ExpandLinkItems(std::string const& prop, std::string const& value, + std::string const& config, cmTarget const* headTarget, + std::vector& items) const; + void LookupLinkItems(std::vector const& names, + std::vector& items) const; std::string ProcessSourceItemCMP0049(const std::string& s); diff --git a/Tests/InterfaceLibrary/CMakeLists.txt b/Tests/InterfaceLibrary/CMakeLists.txt index 81b34e6e4..d4f49c21b 100644 --- a/Tests/InterfaceLibrary/CMakeLists.txt +++ b/Tests/InterfaceLibrary/CMakeLists.txt @@ -8,8 +8,18 @@ target_compile_definitions(iface_nodepends INTERFACE IFACE_DEFINE) add_subdirectory(headerdir) +# Add an interface target in a subdirectory that uses an imported interface. +add_subdirectory(ifacedir) + +# Poison an imported interface with the same name as that in the subdir +# to ensure that the transitive lookup occurs in the subdir. +add_library(imp::iface INTERFACE IMPORTED) +set_property(TARGET imp::iface APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL SOMEPROP) +set_property(TARGET imp::iface PROPERTY INTERFACE_SOMEPROP OFF) +set_property(TARGET imp::iface PROPERTY INTERFACE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist.cpp) + add_executable(InterfaceLibrary definetestexe.cpp) -target_link_libraries(InterfaceLibrary iface_nodepends headeriface) +target_link_libraries(InterfaceLibrary iface_nodepends headeriface subiface) add_subdirectory(libsdir) diff --git a/Tests/InterfaceLibrary/definetestexe.cpp b/Tests/InterfaceLibrary/definetestexe.cpp index e7a10c171..30f292542 100644 --- a/Tests/InterfaceLibrary/definetestexe.cpp +++ b/Tests/InterfaceLibrary/definetestexe.cpp @@ -15,7 +15,9 @@ #error Expected IFACE_HEADER_BUILDDIR #endif +extern int sub(); + int main(int,char**) { - return 0; + return sub(); } diff --git a/Tests/InterfaceLibrary/ifacedir/CMakeLists.txt b/Tests/InterfaceLibrary/ifacedir/CMakeLists.txt new file mode 100644 index 000000000..228715e75 --- /dev/null +++ b/Tests/InterfaceLibrary/ifacedir/CMakeLists.txt @@ -0,0 +1,8 @@ +add_library(imp::iface INTERFACE IMPORTED) +set_property(TARGET imp::iface APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL SOMEPROP) +set_property(TARGET imp::iface PROPERTY INTERFACE_SOMEPROP ON) +set_property(TARGET imp::iface PROPERTY INTERFACE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sub.cpp) + +add_library(subiface INTERFACE) +target_link_libraries(subiface INTERFACE imp::iface) +set_property(TARGET subiface PROPERTY INTERFACE_SOMEPROP ON) diff --git a/Tests/InterfaceLibrary/ifacedir/sub.cpp b/Tests/InterfaceLibrary/ifacedir/sub.cpp new file mode 100644 index 000000000..165a66adb --- /dev/null +++ b/Tests/InterfaceLibrary/ifacedir/sub.cpp @@ -0,0 +1 @@ +int sub() { return 0; }