From 69251f75492a9bd1e3122e8e7ae7888e9c700a57 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 1 Sep 2009 10:37:37 -0400 Subject: [PATCH] Define 'multiplicity' for cyclic dependencies We create target property "LINK_INTERFACE_MULTIPLICITY" and a per-config version "LINK_INTERFACE_MULTIPLICITY_". It sets the number of times a linker should scan through a mutually dependent group of static libraries. The largest value of this property on any target in the group is used. This will help projects link even for extreme cases of cyclic inter-target dependencies. --- Source/cmComputeLinkDepends.cxx | 23 +++++++++++- Source/cmComputeLinkDepends.h | 1 + Source/cmExportFileGenerator.cxx | 8 ++++ Source/cmTarget.cxx | 64 ++++++++++++++++++++++++++++++++ Source/cmTarget.h | 6 +++ 5 files changed, 101 insertions(+), 1 deletion(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 50a63ebd9..b5cee4201 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -900,7 +900,7 @@ cmComputeLinkDepends::MakePendingComponent(unsigned int component) // advantage that the item directly linked by a target requiring // this component will come first which minimizes the number of // repeats needed. - pc.Count = 2; + pc.Count = this->ComputeComponentCount(nl); } // Store the entries to be seen. @@ -909,6 +909,27 @@ cmComputeLinkDepends::MakePendingComponent(unsigned int component) return pc; } +//---------------------------------------------------------------------------- +int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl) +{ + int count = 2; + for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) + { + if(cmTarget* target = this->EntryList[*ni].Target) + { + if(cmTarget::LinkInterface const* iface = + target->GetLinkInterface(this->Config)) + { + if(iface->Multiplicity > count) + { + count = iface->Multiplicity; + } + } + } + } + return count; +} + //---------------------------------------------------------------------------- void cmComputeLinkDepends::DisplayFinalEntries() { diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index d6920101a..f31331994 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -153,6 +153,7 @@ private: void VisitComponent(unsigned int c); void VisitEntry(int index); PendingComponent& MakePendingComponent(unsigned int component); + int ComputeComponentCount(NodeList const& nl); void DisplayFinalEntries(); // Record of the original link line. diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 8c15a2622..b8ef41746 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -161,6 +161,14 @@ cmExportFileGenerator this->SetImportLinkProperty(suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps, properties); + if(iface->Multiplicity > 0) + { + std::string prop = "IMPORTED_LINK_INTERFACE_MULTIPLICITY"; + prop += suffix; + cmOStringStream m; + m << iface->Multiplicity; + properties[prop] = m.str(); + } } } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 4885b0714..8b4ac6f43 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -334,6 +334,18 @@ void cmTarget::DefineProperties(cmake *cm) "If set, this property completely overrides the generic property " "for the named configuration."); + cm->DefineProperty + ("IMPORTED_LINK_INTERFACE_MULTIPLICITY", cmProperty::TARGET, + "Repetition count for cycles of IMPORTED static libraries.", + "This is LINK_INTERFACE_MULTIPLICITY for IMPORTED targets."); + cm->DefineProperty + ("IMPORTED_LINK_INTERFACE_MULTIPLICITY_", cmProperty::TARGET, + "Per-configuration repetition count for cycles of IMPORTED archives.", + "This is the configuration-specific version of " + "IMPORTED_LINK_INTERFACE_MULTIPLICITY. " + "If set, this property completely overrides the generic property " + "for the named configuration."); + cm->DefineProperty ("IMPORTED_LOCATION", cmProperty::TARGET, "Full path to the main file on disk for an IMPORTED target.", @@ -507,6 +519,25 @@ void cmTarget::DefineProperties(cmake *cm) "If set, this property completely overrides the generic property " "for the named configuration."); + cm->DefineProperty + ("LINK_INTERFACE_MULTIPLICITY", cmProperty::TARGET, + "Repetition count for STATIC libraries with cyclic dependencies.", + "When linking to a STATIC library target with cyclic dependencies the " + "linker may need to scan more than once through the archives in the " + "strongly connected component of the dependency graph. " + "CMake by default constructs the link line so that the linker will " + "scan through the component at least twice. " + "This property specifies the minimum number of scans if it is larger " + "than the default. " + "CMake uses the largest value specified by any target in a component."); + cm->DefineProperty + ("LINK_INTERFACE_MULTIPLICITY_", cmProperty::TARGET, + "Per-configuration repetition count for cycles of STATIC libraries.", + "This is the configuration-specific version of " + "LINK_INTERFACE_MULTIPLICITY. " + "If set, this property completely overrides the generic property " + "for the named configuration."); + cm->DefineProperty ("MAP_IMPORTED_CONFIG_", cmProperty::TARGET, "Map from project configuration to IMPORTED target's configuration.", @@ -3877,6 +3908,22 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, info.LinkInterface.Languages); } } + + // Get the cyclic repetition count. + if(this->GetType() == cmTarget::STATIC_LIBRARY) + { + std::string linkProp = "IMPORTED_LINK_INTERFACE_MULTIPLICITY"; + linkProp += suffix; + if(const char* config_reps = this->GetProperty(linkProp.c_str())) + { + sscanf(config_reps, "%u", &info.LinkInterface.Multiplicity); + } + else if(const char* reps = + this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) + { + sscanf(reps, "%u", &info.LinkInterface.Multiplicity); + } + } } //---------------------------------------------------------------------------- @@ -4010,6 +4057,23 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) } } + if(this->GetType() == cmTarget::STATIC_LIBRARY) + { + // How many repetitions are needed if this library has cyclic + // dependencies? + std::string propName = "LINK_INTERFACE_MULTIPLICITY"; + propName += suffix; + if(const char* config_reps = this->GetProperty(propName.c_str())) + { + sscanf(config_reps, "%u", &iface.Multiplicity); + } + else if(const char* reps = + this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) + { + sscanf(reps, "%u", &iface.Multiplicity); + } + } + return true; } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index e0118fcdc..7b8c2ba80 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -249,9 +249,15 @@ public: // Shared library dependencies needed for linking on some platforms. std::vector SharedDeps; + // Number of repetitions of a strongly connected component of two + // or more static libraries. + int Multiplicity; + // Libraries listed for other configurations. // Needed only for OLD behavior of CMP0003. std::vector WrongConfigLibraries; + + LinkInterface(): Multiplicity(0) {} }; /** Get the link interface for the given configuration. Returns 0