[cmake-commits] king committed cmComputeLinkDepends.cxx 1.4 1.5 cmExportBuildFileGenerator.cxx 1.3 1.4 cmExportBuildFileGenerator.h 1.2 1.3 cmExportCommand.cxx 1.9 1.10 cmExportCommand.h 1.8 1.9 cmExportFileGenerator.cxx 1.5 1.6 cmExportFileGenerator.h 1.4 1.5 cmExportInstallFileGenerator.cxx 1.4 1.5 cmTarget.cxx 1.185 1.186 cmTarget.h 1.101 1.102

cmake-commits at cmake.org cmake-commits at cmake.org
Wed Jan 30 17:25:54 EST 2008


Update of /cvsroot/CMake/CMake/Source
In directory public:/mounts/ram/cvs-serv10054/Source

Modified Files:
	cmComputeLinkDepends.cxx cmExportBuildFileGenerator.cxx 
	cmExportBuildFileGenerator.h cmExportCommand.cxx 
	cmExportCommand.h cmExportFileGenerator.cxx 
	cmExportFileGenerator.h cmExportInstallFileGenerator.cxx 
	cmTarget.cxx cmTarget.h 
Log Message:
ENH: Implemented link-interface specification feature.

  - Shared libs and executables with exports may now have
    explicit transitive link dependencies specified
  - Created LINK_INTERFACE_LIBRARIES and related properties
  - Exported targets get the interface libraries as their
    IMPORTED_LINK_LIBRARIES property.
  - The export() and install(EXPORT) commands now give
    an error when a linked target is not included since
    the user can change the interface libraries instead
    of adding the target.


Index: cmExportFileGenerator.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmExportFileGenerator.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- cmExportFileGenerator.h	28 Jan 2008 18:37:59 -0000	1.4
+++ cmExportFileGenerator.h	30 Jan 2008 22:25:52 -0000	1.5
@@ -70,6 +70,11 @@
   void SetImportLinkProperties(const char* config,
                                std::string const& suffix, cmTarget* target,
                                ImportPropertyMap& properties);
+  void SetImportLinkProperties(const char* config,
+                               std::string const& suffix,
+                               cmTarget* target,
+                               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;

Index: cmExportFileGenerator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmExportFileGenerator.cxx,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- cmExportFileGenerator.cxx	28 Jan 2008 19:46:16 -0000	1.5
+++ cmExportFileGenerator.cxx	30 Jan 2008 22:25:52 -0000	1.6
@@ -135,9 +135,18 @@
     }
 
   // Add the transitive link dependencies for this configuration.
-  if(target->GetType() == cmTarget::STATIC_LIBRARY ||
-     target->GetType() == cmTarget::SHARED_LIBRARY)
+  if(cmTargetLinkInterface const* interface =
+     target->GetLinkInterface(config))
+    {
+    // This target provides a link interface, so use it.
+    this->SetImportLinkProperties(config, suffix, target,
+                                  *interface, properties);
+    }
+  else if(target->GetType() == cmTarget::STATIC_LIBRARY ||
+          target->GetType() == cmTarget::SHARED_LIBRARY)
     {
+    // The default link interface for static and shared libraries is
+    // their link implementation library list.
     this->SetImportLinkProperties(config, suffix, target, properties);
     }
 }
@@ -148,9 +157,6 @@
 ::SetImportLinkProperties(const char* config, std::string const& suffix,
                           cmTarget* target, ImportPropertyMap& properties)
 {
-  // Get the makefile in which to lookup target information.
-  cmMakefile* mf = target->GetMakefile();
-
   // Compute which library configuration to link.
   cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
   if(config && cmSystemTools::UpperCase(config) == "DEBUG")
@@ -158,10 +164,10 @@
     linkType = cmTarget::DEBUG;
     }
 
-  // Construct the property value.
+  // Construct the list of libs linked for this configuration.
+  std::vector<std::string> actual_libs;
   cmTarget::LinkLibraryVectorType const& libs =
     target->GetOriginalLinkLibraries();
-  std::string link_libs;
   const char* sep = "";
   for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
       li != libs.end(); ++li)
@@ -174,33 +180,66 @@
       continue;
       }
 
-    // Separate this from the previous entry.
-    link_libs += sep;
-    sep = ";";
+    // Store this entry.
+    actual_libs.push_back(li->first);
+    }
 
+  // Store the entries in the property.
+  this->SetImportLinkProperties(config, suffix, target,
+                                actual_libs, properties);
+}
+
+//----------------------------------------------------------------------------
+void
+cmExportFileGenerator
+::SetImportLinkProperties(const char* config,
+                          std::string const& suffix,
+                          cmTarget* target,
+                          std::vector<std::string> const& libs,
+                          ImportPropertyMap& properties)
+{
+  // Get the makefile in which to lookup target information.
+  cmMakefile* mf = target->GetMakefile();
+
+  // Construct the property value.
+  std::string link_libs;
+  const char* sep = "";
+  for(std::vector<std::string>::const_iterator li = libs.begin();
+      li != libs.end(); ++li)
+    {
     // Append this entry.
-    if(cmTarget* tgt = mf->FindTargetToUse(li->first.c_str()))
+    if(cmTarget* tgt = mf->FindTargetToUse(li->c_str()))
       {
-      // This is a target.  Make sure it is included in the export.
-      if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end())
+      // This is a target.
+      if(tgt->IsImported())
+        {
+        // The target is imported (and therefore is not in the
+        // export).  Append the raw name.
+        link_libs += *li;
+        }
+      else if(this->ExportedTargets.find(tgt) != this->ExportedTargets.end())
         {
         // The target is in the export.  Append it with the export
         // namespace.
         link_libs += this->Namespace;
-        link_libs += li->first;
+        link_libs += *li;
         }
       else
         {
-        // The target is not in the export.  This is probably
-        // user-error.  Warn but add it anyway.
-        this->ComplainAboutMissingTarget(target, li->first.c_str());
-        link_libs += li->first;
+        // The target is not in the export.
+        if(!this->AppendMode)
+          {
+          // We are not appending, so all exported targets should be
+          // known here.  This is probably user-error.
+          this->ComplainAboutMissingTarget(target, li->c_str());
+          }
+        link_libs += *li;
         }
       }
     else
       {
       // Append the raw name.
-      link_libs += li->first;
+      link_libs += *li;
       }
     }
 

Index: cmComputeLinkDepends.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmComputeLinkDepends.cxx,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- cmComputeLinkDepends.cxx	30 Jan 2008 17:15:17 -0000	1.4
+++ cmComputeLinkDepends.cxx	30 Jan 2008 22:25:52 -0000	1.5
@@ -263,17 +263,22 @@
   if(entry.Target)
     {
     // Follow the target dependencies.
-    if(entry.Target->GetType() != cmTarget::EXECUTABLE)
+    if(entry.Target->IsImported())
       {
-      if(entry.Target->IsImported())
-        {
-        this->AddImportedLinkEntries(depender_index, entry.Target);
-        }
-      else
-        {
-        this->AddTargetLinkEntries(depender_index,
-                                   entry.Target->GetOriginalLinkLibraries());
-        }
+      // Imported targets provide their own link information.
+      this->AddImportedLinkEntries(depender_index, entry.Target);
+      }
+    else if(cmTargetLinkInterface const* interface =
+            entry.Target->GetLinkInterface(this->Config))
+      {
+      // This target provides its own link interface information.
+      this->AddLinkEntries(depender_index, *interface);
+      }
+    else if(entry.Target->GetType() != cmTarget::EXECUTABLE)
+      {
+      // Use the target's link implementation as the interface.
+      this->AddTargetLinkEntries(depender_index,
+                                 entry.Target->GetOriginalLinkLibraries());
       }
     }
   else

Index: cmExportBuildFileGenerator.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmExportBuildFileGenerator.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- cmExportBuildFileGenerator.h	28 Jan 2008 18:21:42 -0000	1.2
+++ cmExportBuildFileGenerator.h	30 Jan 2008 22:25:52 -0000	1.3
@@ -19,6 +19,8 @@
 
 #include "cmExportFileGenerator.h"
 
+class cmExportCommand;
+
 /** \class cmExportBuildFileGenerator
  * \brief Generate a file exporting targets from a build tree.
  *
@@ -31,12 +33,17 @@
 class cmExportBuildFileGenerator: public cmExportFileGenerator
 {
 public:
+  cmExportBuildFileGenerator();
+
   /** Set the list of targets to export.  */
   void SetExports(std::vector<cmTarget*> const* exports)
     { this->Exports = exports; }
 
   /** Set whether to append generated code to the output file.  */
   void SetAppendMode(bool append) { this->AppendMode = append; }
+
+  /** Set the command instance through which errors should be reported.  */
+  void SetCommand(cmExportCommand* cmd) { this->ExportCommand = cmd; }
 protected:
   // Implement virtual methods from the superclass.
   virtual bool GenerateMainFile(std::ostream& os);
@@ -52,6 +59,7 @@
                                  ImportPropertyMap& properties);
 
   std::vector<cmTarget*> const* Exports;
+  cmExportCommand* ExportCommand;
 };
 
 #endif

Index: cmTarget.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmTarget.h,v
retrieving revision 1.101
retrieving revision 1.102
diff -u -d -r1.101 -r1.102
--- cmTarget.h	29 Jan 2008 22:30:34 -0000	1.101
+++ cmTarget.h	30 Jan 2008 22:25:52 -0000	1.102
@@ -35,6 +35,20 @@
   ~cmTargetLinkInformationMap();
 };
 
+struct cmTargetLinkInterface: public std::vector<std::string>
+{
+  typedef std::vector<std::string> derived;
+};
+
+struct cmTargetLinkInterfaceMap:
+  public std::map<cmStdString, cmTargetLinkInterface*>
+{
+  typedef std::map<cmStdString, cmTargetLinkInterface*> derived;
+  cmTargetLinkInterfaceMap() {}
+  cmTargetLinkInterfaceMap(cmTargetLinkInterfaceMap const& r);
+  ~cmTargetLinkInterfaceMap();
+};
+
 /** \class cmTarget
  * \brief Represent a library or executable target loaded from a makefile.
  *
@@ -209,6 +223,12 @@
   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
+      such dependencies or for static libraries.  */
+  cmTargetLinkInterface const* GetLinkInterface(const char* config);
+
   /** Get the directory in which this target will be built.  If the
       configuration name is given then the generator will add its
       subdirectory for that configuration.  Otherwise just the canonical
@@ -476,6 +496,10 @@
 
   cmTargetLinkInformationMap LinkInformation;
 
+  // Link interface.
+  cmTargetLinkInterface* ComputeLinkInterface(const char* config);
+  cmTargetLinkInterfaceMap LinkInterface;
+
   // The cmMakefile instance that owns this target.  This should
   // always be set.
   cmMakefile* Makefile;

Index: cmExportCommand.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmExportCommand.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- cmExportCommand.h	28 Jan 2008 18:21:42 -0000	1.8
+++ cmExportCommand.h	30 Jan 2008 22:25:52 -0000	1.9
@@ -19,6 +19,8 @@
 
 #include "cmCommand.h"
 
+class cmExportBuildFileGenerator;
+
 /** \class cmExportLibraryDependenciesCommand
  * \brief Add a test to the lists of tests to run.
  *
@@ -93,6 +95,9 @@
   cmCAEnabler Append;
   cmCAString Namespace;
   cmCAString Filename;
+
+  friend class cmExportBuildFileGenerator;
+  std::string ErrorMessage;
 };
 
 

Index: cmExportBuildFileGenerator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmExportBuildFileGenerator.cxx,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- cmExportBuildFileGenerator.cxx	28 Jan 2008 20:22:07 -0000	1.3
+++ cmExportBuildFileGenerator.cxx	30 Jan 2008 22:25:52 -0000	1.4
@@ -16,6 +16,14 @@
 =========================================================================*/
 #include "cmExportBuildFileGenerator.h"
 
+#include "cmExportCommand.h"
+
+//----------------------------------------------------------------------------
+cmExportBuildFileGenerator::cmExportBuildFileGenerator()
+{
+  this->ExportCommand = 0;
+}
+
 //----------------------------------------------------------------------------
 bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
 {
@@ -116,9 +124,19 @@
 cmExportBuildFileGenerator
 ::ComplainAboutMissingTarget(cmTarget* target, const char* dep)
 {
+  if(!this->ExportCommand || !this->ExportCommand->ErrorMessage.empty())
+    {
+    return;
+    }
+
   cmOStringStream e;
-  e << "WARNING: EXPORT(...) includes target " << target->GetName()
-    << " which links to target \"" << dep
-    << "\" that is not in the export set.";
-  cmSystemTools::Message(e.str().c_str());
+  e << "called with target \"" << target->GetName()
+    << "\" which links to target \"" << dep
+    << "\" that is not in the export list.\n"
+    << "If the link dependency is not part of the public interface "
+    << "consider setting the LINK_INTERFACE_LIBRARIES property on \""
+    << target->GetName() << "\".  Otherwise add it to the export list.  "
+    << "If the link dependency is not easy to reference in this call, "
+    << "consider using the APPEND option with multiple separate calls.";
+  this->ExportCommand->ErrorMessage = e.str();
 }

Index: cmExportInstallFileGenerator.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmExportInstallFileGenerator.cxx,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- cmExportInstallFileGenerator.cxx	28 Jan 2008 20:22:07 -0000	1.4
+++ cmExportInstallFileGenerator.cxx	30 Jan 2008 22:25:52 -0000	1.5
@@ -267,9 +267,13 @@
 ::ComplainAboutMissingTarget(cmTarget* target, const char* dep)
 {
   cmOStringStream e;
-  e << "WARNING: INSTALL(EXPORT \"" << this->Name << "\" ...) "
-    << "includes target " << target->GetName()
-    << " which links to target \"" << dep
-    << "\" that is not in the export set.";
-  cmSystemTools::Message(e.str().c_str());
+  e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
+    << "includes target \"" << target->GetName()
+    << "\" which links to target \"" << dep
+    << "\" that is not in the export set.  "
+    << "If the link dependency is not part of the public interface "
+    << "consider setting the LINK_INTERFACE_LIBRARIES property on "
+    << "target \"" << target->GetName() << "\".  "
+    << "Otherwise add it to the export set.";
+  cmSystemTools::Error(e.str().c_str());
 }

Index: cmTarget.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmTarget.cxx,v
retrieving revision 1.185
retrieving revision 1.186
diff -u -d -r1.185 -r1.186
--- cmTarget.cxx	29 Jan 2008 22:30:34 -0000	1.185
+++ cmTarget.cxx	30 Jan 2008 22:25:52 -0000	1.186
@@ -312,6 +312,28 @@
      "The property is defined only for library and executable targets.");
 
   cm->DefineProperty
+    ("LINK_INTERFACE_LIBRARIES", cmProperty::TARGET,
+     "List public interface libraries for a shared library or executable.",
+     "By default linking to a shared library target transitively "
+     "links to targets with which the library itself was linked.  "
+     "For an executable with exports (see the ENABLE_EXPORTS property) "
+     "no default transitive link dependencies are used.  "
+     "This property replaces the default transitive link dependencies with "
+     "an explict list.  "
+     "When the target is linked into another target the libraries "
+     "listed (and recursively their link interface libraries) will be "
+     "provided to the other target also.  "
+     "If the list is empty then no transitive link dependencies will be "
+     "incorporated when this target is linked into another target even if "
+     "the default set is non-empty.");
+
+  cm->DefineProperty
+    ("LINK_INTERFACE_LIBRARIES_<CONFIG>", cmProperty::TARGET,
+     "Per-configuration list of public interface libraries for a target.",
+     "This is the configuration-specific version of "
+     "LINK_INTERFACE_LIBRARIES.");
+
+  cm->DefineProperty
     ("MAP_IMPORTED_CONFIG_<CONFIG>", cmProperty::TARGET,
      "Map from project configuration to IMPORTED target's configuration.",
      "List configurations of an imported target that may be used for "
@@ -3041,6 +3063,80 @@
 }
 
 //----------------------------------------------------------------------------
+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 &&
+      !this->IsExecutableWithExports()))
+    {
+    return 0;
+    }
+
+  // Lookup any existing link interface for this configuration.
+  std::map<cmStdString, cmTargetLinkInterface*>::iterator
+    i = this->LinkInterface.find(config?config:"");
+  if(i == this->LinkInterface.end())
+    {
+    // Compute the link interface for this configuration.
+    cmTargetLinkInterface* interface = this->ComputeLinkInterface(config);
+
+    // Store the information for this configuration.
+    std::map<cmStdString, cmTargetLinkInterface*>::value_type
+      entry(config?config:"", interface);
+    i = this->LinkInterface.insert(entry).first;
+    }
+
+  return i->second;
+}
+
+//----------------------------------------------------------------------------
+cmTargetLinkInterface* cmTarget::ComputeLinkInterface(const char* config)
+{
+  // Construct the property name suffix for this configuration.
+  std::string suffix = "_";
+  if(config && *config)
+    {
+    suffix += cmSystemTools::UpperCase(config);
+    }
+  else
+    {
+    suffix += "NOCONFIG";
+    }
+
+  // Lookup the link interface libraries.
+  const char* libs = 0;
+  {
+  // Lookup the per-configuration property.
+  std::string propName = "LINK_INTERFACE_LIBRARIES";
+  propName += suffix;
+  libs = this->GetProperty(propName.c_str());
+
+  // If not set, try the generic property.
+  if(!libs)
+    {
+    libs = this->GetProperty("LINK_INTERFACE_LIBRARIES");
+    }
+  }
+
+  // If still not set, there is no link interface.
+  if(!libs)
+    {
+    return 0;
+    }
+
+  // Return the interface libraries even if the list is empty.
+  if(cmTargetLinkInterface* interface = new cmTargetLinkInterface)
+    {
+    cmSystemTools::ExpandListArgument(libs, *interface);
+    return interface;
+    }
+  return 0;
+}
+
+//----------------------------------------------------------------------------
 cmComputeLinkInformation*
 cmTarget::GetLinkInformation(const char* config)
 {
@@ -3088,3 +3184,26 @@
     delete i->second;
     }
 }
+
+//----------------------------------------------------------------------------
+cmTargetLinkInterfaceMap
+::cmTargetLinkInterfaceMap(cmTargetLinkInterfaceMap const& r): derived()
+{
+  // Ideally cmTarget instances should never be copied.  However until
+  // we can make a sweep to remove that, this copy constructor avoids
+  // allowing the resources (LinkInterface) from getting copied.  In
+  // the worst case this will lead to extra cmTargetLinkInterface
+  // instances.  We also enforce in debug mode that the map be emptied
+  // when copied.
+  static_cast<void>(r);
+  assert(r.empty());
+}
+
+//----------------------------------------------------------------------------
+cmTargetLinkInterfaceMap::~cmTargetLinkInterfaceMap()
+{
+  for(derived::iterator i = this->begin(); i != this->end(); ++i)
+    {
+    delete i->second;
+    }
+}

Index: cmExportCommand.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmExportCommand.cxx,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- cmExportCommand.cxx	28 Jan 2008 18:21:42 -0000	1.9
+++ cmExportCommand.cxx	30 Jan 2008 22:25:52 -0000	1.10
@@ -100,12 +100,6 @@
     fname += this->Filename.GetString();
     }
 
-  // If no targets are to be exported we are done.
-  if(this->Targets.GetVector().empty())
-    {
-    return true;
-    }
-
   // Collect the targets to be exported.
   std::vector<cmTarget*> targets;
   for(std::vector<std::string>::const_iterator
@@ -149,6 +143,7 @@
   ebfg.SetNamespace(this->Namespace.GetCString());
   ebfg.SetAppendMode(this->Append.IsEnabled());
   ebfg.SetExports(&targets);
+  ebfg.SetCommand(this);
 
   // Compute the set of configurations exported.
   if(const char* types =
@@ -180,5 +175,12 @@
     return false;
     }
 
+  // Report generated error message if any.
+  if(!this->ErrorMessage.empty())
+    {
+    this->SetError(this->ErrorMessage.c_str());
+    return false;
+    }
+
   return true;
 }



More information about the Cmake-commits mailing list