Преглед на файлове

ENH: Support linking to shared libs with dependent libs

  - Split IMPORTED_LINK_LIBRARIES into two parts:
      IMPORTED_LINK_INTERFACE_LIBRARIES
      IMPORTED_LINK_DEPENDENT_LIBRARIES
  - Add CMAKE_DEPENDENT_SHARED_LIBRARY_MODE to select behavior
  - Set mode to LINK for Darwin (fixes universal binary problem)
  - Update ExportImport test to account for changes
Brad King преди 17 години
родител
ревизия
2cff26fa52

+ 6 - 0
Modules/Platform/Darwin.cmake

@@ -103,6 +103,12 @@ IF(XCODE)
   SET(CMAKE_INCLUDE_SYSTEM_FLAG_CXX)
 ENDIF(XCODE)
 
+# Need to list dependent shared libraries on link line.  When building
+# with -isysroot (for universal binaries), the linker always looks for
+# dependent libraries under the sysroot.  Listing them on the link
+# line works around the problem.
+SET(CMAKE_DEPENDENT_SHARED_LIBRARY_MODE "LINK")
+
 SET(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
 
 SET(CMAKE_C_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS -w)

+ 83 - 22
Source/cmComputeLinkDepends.cxx

@@ -171,6 +171,14 @@ cmComputeLinkDepends::Compute()
     this->FollowLinkEntry(qe);
     }
 
+  // Complete the search of shared library dependencies.
+  while(!this->SharedDepQueue.empty())
+    {
+    // Handle the next entry.
+    this->HandleSharedDependency(this->SharedDepQueue.front());
+    this->SharedDepQueue.pop();
+    }
+
   // Infer dependencies of targets for which they were not known.
   this->InferDependencies();
 
@@ -197,6 +205,20 @@ cmComputeLinkDepends::Compute()
   return this->FinalLinkEntries;
 }
 
+//----------------------------------------------------------------------------
+std::map<cmStdString, int>::iterator
+cmComputeLinkDepends::AllocateLinkEntry(std::string const& item)
+{
+  std::map<cmStdString, int>::value_type
+    index_entry(item, static_cast<int>(this->EntryList.size()));
+  std::map<cmStdString, int>::iterator
+    lei = this->LinkEntryIndex.insert(index_entry).first;
+  this->EntryList.push_back(LinkEntry());
+  this->InferredDependSets.push_back(0);
+  this->EntryConstraintGraph.push_back(EntryConstraintSet());
+  return lei;
+}
+
 //----------------------------------------------------------------------------
 int cmComputeLinkDepends::AddLinkEntry(std::string const& item)
 {
@@ -209,14 +231,7 @@ int cmComputeLinkDepends::AddLinkEntry(std::string const& item)
     }
 
   // Allocate a spot for the item entry.
-  {
-  std::map<cmStdString, int>::value_type
-    index_entry(item, static_cast<int>(this->EntryList.size()));
-  lei = this->LinkEntryIndex.insert(index_entry).first;
-  this->EntryList.push_back(LinkEntry());
-  this->InferredDependSets.push_back(0);
-  this->EntryConstraintGraph.push_back(EntryConstraintSet());
-  }
+  lei = this->AllocateLinkEntry(item);
 
   // Initialize the item entry.
   int index = lei->second;
@@ -263,18 +278,17 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
   if(entry.Target)
     {
     // Follow the target dependencies.
-    if(entry.Target->IsImported())
-      {
-      // Imported targets provide their own link information.
-      this->AddImportedLinkEntries(depender_index, entry.Target);
-      }
-    else if(cmTargetLinkInterface const* interface =
-            entry.Target->GetLinkInterface(this->Config))
+    if(cmTargetLinkInterface const* interface =
+       entry.Target->GetLinkInterface(this->Config))
       {
       // This target provides its own link interface information.
-      this->AddLinkEntries(depender_index, *interface);
+      this->AddLinkEntries(depender_index, interface->Libraries);
+
+      // Handle dependent shared libraries.
+      this->QueueSharedDependencies(depender_index, interface->SharedDeps);
       }
-    else if(entry.Target->GetType() != cmTarget::EXECUTABLE)
+    else if(!entry.Target->IsImported() &&
+            entry.Target->GetType() != cmTarget::EXECUTABLE)
       {
       // Use the target's link implementation as the interface.
       this->AddTargetLinkEntries(depender_index,
@@ -289,13 +303,60 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
 }
 
 //----------------------------------------------------------------------------
-void cmComputeLinkDepends::AddImportedLinkEntries(int depender_index,
-                                                  cmTarget* target)
+void
+cmComputeLinkDepends
+::QueueSharedDependencies(int depender_index,
+                          std::vector<std::string> const& deps)
+{
+  for(std::vector<std::string>::const_iterator li = deps.begin();
+      li != deps.end(); ++li)
+    {
+    SharedDepEntry qe;
+    qe.Item = *li;
+    qe.DependerIndex = depender_index;
+    this->SharedDepQueue.push(qe);
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
 {
-  if(std::vector<std::string> const* libs =
-     target->GetImportedLinkLibraries(this->Config))
+  // Check if the target already has an entry.
+  std::map<cmStdString, int>::iterator lei =
+    this->LinkEntryIndex.find(dep.Item);
+  if(lei == this->LinkEntryIndex.end())
     {
-    this->AddLinkEntries(depender_index, *libs);
+    // Allocate a spot for the item entry.
+    lei = this->AllocateLinkEntry(dep.Item);
+
+    // Initialize the item entry.
+    LinkEntry& entry = this->EntryList[lei->second];
+    entry.Item = dep.Item;
+    entry.Target = this->Makefile->FindTargetToUse(dep.Item.c_str());
+
+    // This item was added specifically because it is a dependent
+    // shared library.  It may get special treatment
+    // in cmComputeLinkInformation.
+    entry.IsSharedDep = true;
+    }
+
+  // Get the link entry for this target.
+  int index = lei->second;
+  LinkEntry& entry = this->EntryList[index];
+
+  // This shared library dependency must be preceded by the item that
+  // listed it.
+  this->EntryConstraintGraph[index].insert(dep.DependerIndex);
+
+  // Target items may have their own dependencies.
+  if(entry.Target)
+    {
+    if(cmTargetLinkInterface const* interface =
+       entry.Target->GetLinkInterface(this->Config))
+      {
+      // We use just the shared dependencies, not the interface.
+      this->QueueSharedDependencies(index, interface->SharedDeps);
+      }
     }
 }
 

+ 19 - 3
Source/cmComputeLinkDepends.h

@@ -41,8 +41,10 @@ public:
   {
     std::string Item;
     cmTarget* Target;
-    LinkEntry(): Item(), Target(0) {}
-    LinkEntry(LinkEntry const& r): Item(r.Item), Target(r.Target) {}
+    bool IsSharedDep;
+    LinkEntry(): Item(), Target(0), IsSharedDep(false) {}
+    LinkEntry(LinkEntry const& r):
+      Item(r.Item), Target(r.Target), IsSharedDep(r.IsSharedDep) {}
   };
 
   typedef std::vector<LinkEntry> EntryVector;
@@ -65,8 +67,9 @@ private:
 
   typedef cmTarget::LinkLibraryVectorType LinkLibraryVectorType;
 
+  std::map<cmStdString, int>::iterator
+  AllocateLinkEntry(std::string const& item);
   int AddLinkEntry(std::string const& item);
-  void AddImportedLinkEntries(int depender_index, cmTarget* target);
   void AddVarLinkEntries(int depender_index, const char* value);
   void AddTargetLinkEntries(int depender_index,
                             LinkLibraryVectorType const& libs);
@@ -86,6 +89,19 @@ private:
   std::queue<BFSEntry> BFSQueue;
   void FollowLinkEntry(BFSEntry const&);
 
+  // Shared libraries that are included only because they are
+  // dependencies of other shared libraries, not because they are part
+  // of the interface.
+  struct SharedDepEntry
+  {
+    std::string Item;
+    int DependerIndex;
+  };
+  std::queue<SharedDepEntry> SharedDepQueue;
+  void QueueSharedDependencies(int depender_index,
+                               std::vector<std::string> const& deps);
+  void HandleSharedDependency(SharedDepEntry const& dep);
+
   // Dependency inferral for each link item.
   struct DependSet: public std::set<int> {};
   struct DependSetList: public std::vector<DependSet> {};

+ 50 - 8
Source/cmComputeLinkInformation.cxx

@@ -234,6 +234,21 @@ cmComputeLinkInformation
   // Setup framework support.
   this->ComputeFrameworkInfo();
 
+  // Choose a mode for dealing with shared library dependencies.
+  this->SharedDependencyMode = SharedDepModeNone;
+  if(const char* mode =
+     this->Makefile->GetDefinition("CMAKE_DEPENDENT_SHARED_LIBRARY_MODE"))
+    {
+    if(strcmp(mode, "LINK") == 0)
+      {
+      this->SharedDependencyMode = SharedDepModeLink;
+      }
+    else if(strcmp(mode, "DIR") == 0)
+      {
+      this->SharedDependencyMode = SharedDepModeDir;
+      }
+    }
+
   // Get the implicit link directories for this platform.
   if(const char* implicitLinks =
      (this->Makefile->GetDefinition
@@ -335,7 +350,7 @@ bool cmComputeLinkInformation::Compute()
         lei = linkEntries.begin();
       lei != linkEntries.end(); ++lei)
     {
-    this->AddItem(lei->Item, lei->Target);
+    this->AddItem(lei->Item, lei->Target, lei->IsSharedDep);
     }
 
   // Restore the target link type so the correct system runtime
@@ -358,8 +373,14 @@ bool cmComputeLinkInformation::Compute()
 
 //----------------------------------------------------------------------------
 void cmComputeLinkInformation::AddItem(std::string const& item,
-                                       cmTarget* tgt)
+                                       cmTarget* tgt, bool isSharedDep)
 {
+  // If dropping shared library dependencies, ignore them.
+  if(isSharedDep && this->SharedDependencyMode == SharedDepModeNone)
+    {
+    return;
+    }
+
   // Compute the proper name to use to link this library.
   const char* config = this->Config;
   bool impexe = (tgt && tgt->IsExecutableWithExports());
@@ -370,12 +391,6 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
     return;
     }
 
-  // Keep track of shared libraries linked.
-  if(tgt && tgt->GetType() == cmTarget::SHARED_LIBRARY)
-    {
-    this->SharedLibrariesLinked.insert(tgt);
-    }
-
   if(tgt && (tgt->GetType() == cmTarget::STATIC_LIBRARY ||
              tgt->GetType() == cmTarget::SHARED_LIBRARY ||
              tgt->GetType() == cmTarget::MODULE_LIBRARY ||
@@ -401,6 +416,14 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
         (this->UseImportLibrary &&
          (impexe || tgt->GetType() == cmTarget::SHARED_LIBRARY));
 
+      // Handle shared dependencies in directory mode.
+      if(isSharedDep && this->SharedDependencyMode == SharedDepModeDir)
+        {
+        std::string dir = tgt->GetDirectory(config, implib);
+        this->SharedDependencyDirectories.push_back(dir);
+        return;
+        }
+
       // Pass the full path to the target file.
       std::string lib = tgt->GetFullPath(config, implib);
       this->Depends.push_back(lib);
@@ -411,6 +434,7 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
         // link.
         std::string fw = tgt->GetDirectory(config, implib);
         this->AddFrameworkItem(fw);
+        this->SharedLibrariesLinked.insert(tgt);
         }
       else
         {
@@ -705,6 +729,12 @@ void cmComputeLinkInformation::AddTargetItem(std::string const& item,
     this->Items.push_back(Item(this->LibLinkFileFlag, false));
     }
 
+  // Keep track of shared library targets linked.
+  if(target->GetType() == cmTarget::SHARED_LIBRARY)
+    {
+    this->SharedLibrariesLinked.insert(target);
+    }
+
   // Now add the full path to the library.
   this->Items.push_back(Item(item, true));
 }
@@ -991,6 +1021,18 @@ void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
     {
     this->AddLinkerSearchDirectories(this->OldLinkDirs);
     }
+
+  // Help the linker find dependent shared libraries.
+  if(this->SharedDependencyMode == SharedDepModeDir)
+    {
+    // TODO: These directories should probably be added to the runtime
+    // path ordering analysis.  However they are a bit different.
+    // They should be placed both on the -L path and in the rpath.
+    // The link-with-runtime-path feature above should be replaced by
+    // this.
+    this->AddLinkerSearchDirectories(this->SharedDependencyDirectories);
+    }
+
 }
 
 //----------------------------------------------------------------------------

+ 11 - 1
Source/cmComputeLinkInformation.h

@@ -58,7 +58,7 @@ public:
   std::string GetChrpathTool();
   std::set<cmTarget*> const& GetSharedLibrariesLinked();
 private:
-  void AddItem(std::string const& item, cmTarget* tgt);
+  void AddItem(std::string const& item, cmTarget* tgt, bool isSharedDep);
 
   // Output information.
   ItemVector Items;
@@ -78,6 +78,14 @@ private:
   const char* Config;
   const char* LinkLanguage;
 
+  // Modes for dealing with dependent shared libraries.
+  enum SharedDepMode
+  {
+    SharedDepModeNone, // Drop
+    SharedDepModeDir,  // Use in runtime information
+    SharedDepModeLink  // List file on link line
+  };
+
   // System info.
   bool UseImportLibrary;
   const char* LoaderFlag;
@@ -88,6 +96,7 @@ private:
   std::string RuntimeSep;
   std::string RuntimeAlways;
   bool RuntimeUseChrpath;
+  SharedDepMode SharedDependencyMode;
 
   // Link type adjustment.
   void ComputeLinkTypeInfo();
@@ -134,6 +143,7 @@ private:
   void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
   std::set<cmStdString> DirectoriesEmmitted;
   std::set<cmStdString> ImplicitLinkDirs;
+  std::vector<std::string> SharedDependencyDirectories;
 
   // Linker search path compatibility mode.
   std::vector<std::string> OldLinkDirs;

+ 2 - 0
Source/cmDocumentVariables.cxx

@@ -1104,5 +1104,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
                      cmProperty::VARIABLE,0,0);
   cm->DefineProperty("CMAKE_SHARED_MODULE_RUNTIME_<LANG>_FLAG_SEP",
                      cmProperty::VARIABLE,0,0);
+  cm->DefineProperty("CMAKE_DEPENDENT_SHARED_LIBRARY_MODE",
+                     cmProperty::VARIABLE,0,0);
 
 }

+ 24 - 7
Source/cmExportFileGenerator.cxx

@@ -139,7 +139,12 @@ cmExportFileGenerator
      target->GetLinkInterface(config))
     {
     // This target provides a link interface, so use it.
-    this->SetImportLinkProperties(suffix, target, *interface, properties);
+    this->SetImportLinkProperty(suffix, target,
+                                "IMPORTED_LINK_INTERFACE_LIBRARIES",
+                                interface->Libraries, properties);
+    this->SetImportLinkProperty(suffix, target,
+                                "IMPORTED_LINK_DEPENDENT_LIBRARIES",
+                                interface->SharedDeps, properties);
     }
   else if(target->GetType() == cmTarget::STATIC_LIBRARY ||
           target->GetType() == cmTarget::SHARED_LIBRARY)
@@ -183,17 +188,26 @@ cmExportFileGenerator
     }
 
   // Store the entries in the property.
-  this->SetImportLinkProperties(suffix, target, actual_libs, properties);
+  this->SetImportLinkProperty(suffix, target,
+                              "IMPORTED_LINK_INTERFACE_LIBRARIES",
+                              actual_libs, properties);
 }
 
 //----------------------------------------------------------------------------
 void
 cmExportFileGenerator
-::SetImportLinkProperties(std::string const& suffix,
-                          cmTarget* target,
-                          std::vector<std::string> const& libs,
-                          ImportPropertyMap& properties)
+::SetImportLinkProperty(std::string const& suffix,
+                        cmTarget* target,
+                        const char* propName,
+                        std::vector<std::string> const& libs,
+                        ImportPropertyMap& properties)
 {
+  // Skip the property if there are no libraries.
+  if(libs.empty())
+    {
+    return;
+    }
+
   // Get the makefile in which to lookup target information.
   cmMakefile* mf = target->GetMakefile();
 
@@ -233,6 +247,9 @@ cmExportFileGenerator
           // known here.  This is probably user-error.
           this->ComplainAboutMissingTarget(target, li->c_str());
           }
+        // Assume the target will be exported by another command.
+        // Append it with the export namespace.
+        link_libs += this->Namespace;
         link_libs += *li;
         }
       }
@@ -244,7 +261,7 @@ cmExportFileGenerator
     }
 
   // Store the property.
-  std::string prop = "IMPORTED_LINK_LIBRARIES";
+  std::string prop = propName;
   prop += suffix;
   properties[prop] = link_libs;
 }

+ 4 - 4
Source/cmExportFileGenerator.h

@@ -70,10 +70,10 @@ protected:
   void SetImportLinkProperties(const char* config,
                                std::string const& suffix, cmTarget* target,
                                ImportPropertyMap& properties);
-  void SetImportLinkProperties(std::string const& suffix,
-                               cmTarget* target,
-                               std::vector<std::string> const& libs,
-                               ImportPropertyMap& properties);
+  void SetImportLinkProperty(std::string const& suffix,
+                             cmTarget* target, const char* propName,
+                             std::vector<std::string> const& libs,
+                             ImportPropertyMap& properties);
 
   /** Each subclass knows how to generate its kind of export file.  */
   virtual bool GenerateMainFile(std::ostream& os) = 0;

+ 129 - 29
Source/cmTarget.cxx

@@ -188,15 +188,38 @@ void cmTarget::DefineProperties(cmake *cm)
      "from which the target is imported.");
 
   cm->DefineProperty
-    ("IMPORTED_LINK_LIBRARIES", cmProperty::TARGET,
-     "Transitive link dependencies of an IMPORTED target.",
-     "Lists dependencies that must be linked when an IMPORTED library "
+    ("IMPORTED_LINK_DEPENDENT_LIBRARIES", cmProperty::TARGET,
+     "Dependent shared libraries of an imported shared library.",
+     "Shared libraries may be linked to other shared libraries as part "
+     "of their implementation.  On some platforms the linker searches "
+     "for the dependent libraries of shared libraries they are including "
+     "in the link.  CMake gives the paths to these libraries to the linker "
+     "by listing them on the link line explicitly.  This property lists "
+     "the dependent shared libraries of an imported library.  The list "
+     "should be disjoint from the list of interface libraries in the "
+     "IMPORTED_LINK_INTERFACE_LIBRARIES property.  On platforms requiring "
+     "dependent shared libraries to be found at link time CMake uses this "
+     "list to add the dependent libraries to the link command line.");
+
+  cm->DefineProperty
+    ("IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>", cmProperty::TARGET,
+     "Per-configuration version of IMPORTED_LINK_DEPENDENT_LIBRARIES.",
+     "This property is used when loading settings for the <CONFIG> "
+     "configuration of an imported target.  "
+     "Configuration names correspond to those provided by the project "
+     "from which the target is imported.");
+
+  cm->DefineProperty
+    ("IMPORTED_LINK_INTERFACE_LIBRARIES", cmProperty::TARGET,
+     "Transitive link interface of an IMPORTED target.",
+     "Lists libraries whose interface is included when an IMPORTED library "
      "target is linked to another target.  "
+     "The libraries will be included on the link line for the target.  "
      "Ignored for non-imported targets.");
 
   cm->DefineProperty
-    ("IMPORTED_LINK_LIBRARIES_<CONFIG>", cmProperty::TARGET,
-     "Per-configuration version of IMPORTED_LINK_LIBRARIES property.",
+    ("IMPORTED_LINK_INTERFACE_LIBRARIES_<CONFIG>", cmProperty::TARGET,
+     "Per-configuration version of IMPORTED_LINK_INTERFACE_LIBRARIES.",
      "This property is used when loading settings for the <CONFIG> "
      "configuration of an imported target.  "
      "Configuration names correspond to those provided by the project "
@@ -3045,43 +3068,56 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
       }
     }
 
-  // Get the link dependencies.
+  // Get the link interface.
   {
-  std::string linkProp = "IMPORTED_LINK_LIBRARIES";
+  std::string linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
   linkProp += suffix;
   if(const char* config_libs = this->GetProperty(linkProp.c_str()))
     {
-    cmSystemTools::ExpandListArgument(config_libs, info.LinkLibraries);
+    cmSystemTools::ExpandListArgument(config_libs,
+                                      info.LinkInterface.Libraries);
     }
-  else if(const char* libs = this->GetProperty("IMPORTED_LINK_LIBRARIES"))
+  else if(const char* libs =
+          this->GetProperty("IMPORTED_LINK_INTERFACE_LIBRARIES"))
     {
-    cmSystemTools::ExpandListArgument(libs, info.LinkLibraries);
+    cmSystemTools::ExpandListArgument(libs,
+                                      info.LinkInterface.Libraries);
     }
   }
-}
 
-//----------------------------------------------------------------------------
-std::vector<std::string> const*
-cmTarget::GetImportedLinkLibraries(const char* config)
-{
-  if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+  // Get the link dependencies.
+  {
+  std::string linkProp = "IMPORTED_LINK_DEPENDENT_LIBRARIES";
+  linkProp += suffix;
+  if(const char* config_libs = this->GetProperty(linkProp.c_str()))
     {
-    return &info->LinkLibraries;
+    cmSystemTools::ExpandListArgument(config_libs,
+                                      info.LinkInterface.SharedDeps);
     }
-  else
+  else if(const char* libs =
+          this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES"))
     {
-    return 0;
+    cmSystemTools::ExpandListArgument(libs, info.LinkInterface.SharedDeps);
     }
+  }
 }
 
 //----------------------------------------------------------------------------
 cmTargetLinkInterface const* cmTarget::GetLinkInterface(const char* config)
 {
-  // Link interfaces are supported only for non-imported shared
-  // libraries and executables that export symbols.  Imported targets
-  // provide their own link information.
-  if(this->IsImported() ||
-     (this->GetType() != cmTarget::SHARED_LIBRARY &&
+  // Imported targets have their own link interface.
+  if(this->IsImported())
+    {
+    if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+      {
+      return &info->LinkInterface;
+      }
+    return 0;
+    }
+
+  // Link interfaces are supported only for shared libraries and
+  // executables that export symbols.
+  if((this->GetType() != cmTarget::SHARED_LIBRARY &&
       !this->IsExecutableWithExports()))
     {
     return 0;
@@ -3139,13 +3175,77 @@ cmTargetLinkInterface* cmTarget::ComputeLinkInterface(const char* config)
     return 0;
     }
 
-  // Return the interface libraries even if the list is empty.
-  if(cmTargetLinkInterface* interface = new cmTargetLinkInterface)
+  // Allocate the interface.
+  cmTargetLinkInterface* interface = new cmTargetLinkInterface;
+  if(!interface)
     {
-    cmSystemTools::ExpandListArgument(libs, *interface);
-    return interface;
+    return 0;
+    }
+
+  // Expand the list of libraries in the interface.
+  cmSystemTools::ExpandListArgument(libs, interface->Libraries);
+
+  // Now we need to construct a list of shared library dependencies
+  // not included in the interface.
+  if(this->GetType() == cmTarget::SHARED_LIBRARY)
+    {
+    // Use a set to keep track of what libraries have been emitted to
+    // either list.
+    std::set<cmStdString> emitted;
+    for(std::vector<std::string>::const_iterator
+          li = interface->Libraries.begin();
+        li != interface->Libraries.end(); ++li)
+      {
+      emitted.insert(*li);
+      }
+
+    // Compute which library configuration to link.
+    cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
+    if(config && cmSystemTools::UpperCase(config) == "DEBUG")
+      {
+      linkType = cmTarget::DEBUG;
+      }
+
+    // Construct the list of libs linked for this configuration.
+    cmTarget::LinkLibraryVectorType const& libs =
+      this->GetOriginalLinkLibraries();
+    for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
+        li != libs.end(); ++li)
+      {
+      // Skip entries that will resolve to the target itself, are empty,
+      // or are not meant for this configuration.
+      if(li->first == this->GetName() || li->first.empty() ||
+         !(li->second == cmTarget::GENERAL || li->second == linkType))
+        {
+        continue;
+        }
+
+      // Skip entries that have already been emitted into either list.
+      if(!emitted.insert(li->first).second)
+        {
+        continue;
+        }
+
+      // Add this entry if it is a shared library.
+      if(cmTarget* tgt = this->Makefile->FindTargetToUse(li->first.c_str()))
+        {
+        if(tgt->GetType() == cmTarget::SHARED_LIBRARY)
+          {
+          interface->SharedDeps.push_back(li->first);
+          }
+        }
+      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.
+        }
+      }
     }
-  return 0;
+
+  // Return the completed interface.
+  return interface;
 }
 
 //----------------------------------------------------------------------------

+ 7 - 8
Source/cmTarget.h

@@ -35,9 +35,13 @@ struct cmTargetLinkInformationMap:
   ~cmTargetLinkInformationMap();
 };
 
-struct cmTargetLinkInterface: public std::vector<std::string>
+struct cmTargetLinkInterface
 {
-  typedef std::vector<std::string> derived;
+  // Libraries listed in the interface.
+  std::vector<std::string> Libraries;
+
+  // Shared library dependencies needed for linking on some platforms.
+  std::vector<std::string> SharedDeps;
 };
 
 struct cmTargetLinkInterfaceMap:
@@ -218,11 +222,6 @@ public:
 
   bool IsImported() const {return this->IsImportedTarget;}
 
-  /** Get link libraries for the given configuration of an imported
-      target.  */
-  std::vector<std::string> const*
-  GetImportedLinkLibraries(const char* config);
-
   /** Get the library interface dependencies.  This is the set of
       libraries from which something that links to this target may
       also receive symbols.  Returns 0 if the user has not specified
@@ -487,7 +486,7 @@ private:
     std::string Location;
     std::string SOName;
     std::string ImportLibrary;
-    std::vector<std::string> LinkLibraries;
+    cmTargetLinkInterface LinkInterface;
   };
   typedef std::map<cmStdString, ImportInfo> ImportInfoMapType;
   ImportInfoMapType ImportInfoMap;

+ 5 - 10
Tests/ExportImport/Export/CMakeLists.txt

@@ -32,18 +32,12 @@ set_property(TARGET testLib4 PROPERTY FRAMEWORK 1)
 add_executable(testExe3 testExe3.c)
 set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1)
 
-# Install helper targets that are not part of the interface.
-install(
-  TARGETS testExe2libImp testLib3Imp
-  RUNTIME DESTINATION bin
-  LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib
-  )
-
 # Install and export from install tree.
 install(
-  TARGETS testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
-          testExe2lib
+  TARGETS
+  testExe2libImp testLib3Imp
+  testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
+  testExe2lib
   EXPORT exp
   RUNTIME DESTINATION bin
   LIBRARY DESTINATION lib
@@ -55,6 +49,7 @@ install(EXPORT exp NAMESPACE exp_ DESTINATION lib/exp)
 
 # Export from build tree.
 export(TARGETS testExe1 testLib1 testLib2 testLib3
+  testExe2libImp testLib3Imp
   NAMESPACE bld_
   FILE ExportBuildTree.cmake
   )