[cmake-commits] king committed CMakeLists.txt 1.394 1.395 cmComputeLinkInformation.cxx 1.19 1.20 cmComputeLinkInformation.h 1.13 1.14 cmOrderDirectories.cxx NONE 1.1 cmOrderDirectories.h NONE 1.1 cmOrderRuntimeDirectories.cxx 1.1 NONE cmOrderRuntimeDirectories.h 1.1 NONE cmTarget.cxx 1.198 1.199 cmTarget.h 1.106 1.107

cmake-commits at cmake.org cmake-commits at cmake.org
Thu Feb 21 11:41:13 EST 2008


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

Modified Files:
	CMakeLists.txt cmComputeLinkInformation.cxx 
	cmComputeLinkInformation.h cmTarget.cxx cmTarget.h 
Added Files:
	cmOrderDirectories.cxx cmOrderDirectories.h 
Removed Files:
	cmOrderRuntimeDirectories.cxx cmOrderRuntimeDirectories.h 
Log Message:
ENH: Better linker search path computation.

  - Use linker search path -L.. -lfoo for lib w/out soname
    when platform sets CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME
  - Rename cmOrderRuntimeDirectories to cmOrderDirectories
    and generalize it for both soname constraints and link
    library constraints
  - Use cmOrderDirectories to order -L directories based
    on all needed constraints
  - Avoid processing implicit link directories
  - For CMAKE_OLD_LINK_PATHS add constraints from libs
    producing them to produce old ordering


Index: cmComputeLinkInformation.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmComputeLinkInformation.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- cmComputeLinkInformation.h	6 Feb 2008 18:34:44 -0000	1.13
+++ cmComputeLinkInformation.h	21 Feb 2008 16:41:11 -0000	1.14
@@ -26,7 +26,7 @@
 class cmLocalGenerator;
 class cmMakefile;
 class cmTarget;
-class cmOrderRuntimeDirectories;
+class cmOrderDirectories;
 
 /** \class cmComputeLinkInformation
  * \brief Compute link information for a target in one configuration.
@@ -89,9 +89,10 @@
   // Modes for dealing with dependent shared libraries.
   enum SharedDepMode
   {
-    SharedDepModeNone, // Drop
-    SharedDepModeDir,  // Use in runtime information
-    SharedDepModeLink  // List file on link line
+    SharedDepModeNone,   // Drop
+    SharedDepModeDir,    // List dir in -rpath-link flag
+    SharedDepModeLibDir, // List dir in linker search path
+    SharedDepModeLink    // List file on link line
   };
 
   // System info.
@@ -104,6 +105,8 @@
   std::string RuntimeSep;
   std::string RuntimeAlways;
   bool RuntimeUseChrpath;
+  bool NoSONameUsesPath;
+  bool LinkWithRuntimePath;
   std::string RPathLinkFlag;
   SharedDepMode SharedDependencyMode;
 
@@ -124,7 +127,6 @@
   std::vector<std::string> SharedLinkExtensions;
   std::vector<std::string> LinkExtensions;
   std::set<cmStdString> LinkPrefixes;
-  cmsys::RegularExpression RemoveLibraryExtension;
   cmsys::RegularExpression ExtractStaticLibraryName;
   cmsys::RegularExpression ExtractSharedLibraryName;
   cmsys::RegularExpression ExtractAnyLibraryName;
@@ -133,7 +135,7 @@
   std::string CreateExtensionRegex(std::vector<std::string> const& exts);
   std::string NoCaseExpression(const char* str);
 
-  // Handling of link items that are not targets or full file paths.
+  // Handling of link items.
   void AddTargetItem(std::string const& item, cmTarget* target);
   void AddFullItem(std::string const& item);
   bool CheckImplicitDirItem(std::string const& item);
@@ -141,6 +143,8 @@
   void AddDirectoryItem(std::string const& item);
   void AddFrameworkItem(std::string const& item);
   void DropDirectoryItem(std::string const& item);
+  bool CheckSharedLibNoSOName(std::string const& item);
+  void AddSharedLibNoSOName(std::string const& item);
 
   // Framework info.
   void ComputeFrameworkInfo();
@@ -149,23 +153,22 @@
   cmsys::RegularExpression SplitFramework;
 
   // Linker search path computation.
-  void ComputeLinkerSearchDirectories();
-  void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
-  std::set<cmStdString> DirectoriesEmmitted;
+  cmOrderDirectories* OrderLinkerSearchPath;
+  void FinishLinkerSearchDirectories();
   std::set<cmStdString> ImplicitLinkDirs;
 
   // Linker search path compatibility mode.
-  std::vector<std::string> OldLinkDirs;
+  std::vector<std::string> OldLinkDirItems;
   bool OldLinkDirMode;
   bool HaveUserFlagItem;
 
   // Runtime path computation.
-  cmOrderRuntimeDirectories* OrderRuntimeSearchPath;
+  cmOrderDirectories* OrderRuntimeSearchPath;
   void AddLibraryRuntimeInfo(std::string const& fullPath, cmTarget* target);
   void AddLibraryRuntimeInfo(std::string const& fullPath);
 
   // Dependent library path computation.
-  cmOrderRuntimeDirectories* OrderDependentRPath;
+  cmOrderDirectories* OrderDependentRPath;
 };
 
 #endif

Index: cmComputeLinkInformation.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmComputeLinkInformation.cxx,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- cmComputeLinkInformation.cxx	7 Feb 2008 01:14:55 -0000	1.19
+++ cmComputeLinkInformation.cxx	21 Feb 2008 16:41:11 -0000	1.20
@@ -17,7 +17,7 @@
 #include "cmComputeLinkInformation.h"
 
 #include "cmComputeLinkDepends.h"
-#include "cmOrderRuntimeDirectories.h"
+#include "cmOrderDirectories.h"
 
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
@@ -212,6 +212,30 @@
 In our implementation we add all dependent libraries to the runtime
 path computation.  Then the auto-generated RPATH will find everything.
 
+------------------------------------------------------------------------------
+Notes about shared libraries with not builtin soname:
+
+Some UNIX shared libraries may be created with no builtin soname.  On
+some platforms such libraries cannot be linked using the path to their
+location because the linker will copy the path into the field used to
+find the library at runtime.
+
+  Apple:    ../libfoo.dylib  ==>  libfoo.dylib  # ok, uses install_name
+  SGI:      ../libfoo.so     ==>  libfoo.so     # ok
+  AIX:      ../libfoo.so     ==>  libfoo.so     # ok
+  Linux:    ../libfoo.so     ==>  ../libfoo.so  # bad
+  HP-UX:    ../libfoo.so     ==>  ../libfoo.so  # bad
+  Sun:      ../libfoo.so     ==>  ../libfoo.so  # bad
+  FreeBSD:  ../libfoo.so     ==>  ../libfoo.so  # bad
+
+In order to link these libraries we need to use the old-style split
+into -L.. and -lfoo options.  This should be fairly safe because most
+problems with -lfoo options were related to selecting shared libraries
+instead of static but in this case we want the shared lib.  Link
+directory ordering needs to be done to make sure these shared
+libraries are found first.  There should be very few restrictions
+because this need be done only for shared libraries without soname-s.
+
 */
 
 //----------------------------------------------------------------------------
@@ -229,9 +253,12 @@
   this->Config = config;
 
   // Allocate internals.
+  this->OrderLinkerSearchPath =
+    new cmOrderDirectories(this->GlobalGenerator, target->GetName(),
+                           "linker search path");
   this->OrderRuntimeSearchPath =
-    new cmOrderRuntimeDirectories(this->GlobalGenerator, target->GetName(),
-                                  "runtime path");
+    new cmOrderDirectories(this->GlobalGenerator, target->GetName(),
+                           "runtime search path");
   this->OrderDependentRPath = 0;
 
   // Get the language used for linking this target.
@@ -298,6 +325,18 @@
     this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar.c_str());
     }
 
+  // Check if we need to include the runtime search path at link time.
+  {
+  std::string var = "CMAKE_SHARED_LIBRARY_LINK_";
+  var += this->LinkLanguage;
+  var += "_WITH_RUNTIME_PATH";
+  this->LinkWithRuntimePath = this->Makefile->IsOn(var.c_str());
+  }
+
+  // Check the platform policy for missing soname case.
+  this->NoSONameUsesPath =
+    this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");
+
   // Get link type information.
   this->ComputeLinkTypeInfo();
 
@@ -315,24 +354,16 @@
     }
   else if(this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS"))
     {
-    this->SharedDependencyMode = SharedDepModeDir;
+    this->SharedDependencyMode = SharedDepModeLibDir;
     }
   else if(!this->RPathLinkFlag.empty())
     {
     this->SharedDependencyMode = SharedDepModeDir;
-    }
-  if(this->SharedDependencyMode == SharedDepModeDir)
-    {
     this->OrderDependentRPath =
-      new cmOrderRuntimeDirectories(this->GlobalGenerator, target->GetName(),
-                                    "dependent library path");
+      new cmOrderDirectories(this->GlobalGenerator, target->GetName(),
+                             "dependent library path");
     }
 
-  // Add the search path entries requested by the user to the runtime
-  // path computation.
-  this->OrderRuntimeSearchPath->AddDirectories(
-     this->Target->GetLinkDirectories());
-
   // Get the implicit link directories for this platform.
   if(const char* implicitLinks =
      (this->Makefile->GetDefinition
@@ -348,6 +379,21 @@
       }
     }
 
+  // Add the search path entries requested by the user to path ordering.
+  this->OrderLinkerSearchPath
+    ->AddUserDirectories(this->Target->GetLinkDirectories());
+  this->OrderRuntimeSearchPath
+    ->AddUserDirectories(this->Target->GetLinkDirectories());
+  this->OrderLinkerSearchPath
+    ->SetImplicitDirectories(this->ImplicitLinkDirs);
+  this->OrderRuntimeSearchPath
+    ->SetImplicitDirectories(this->ImplicitLinkDirs);
+  if(this->OrderDependentRPath)
+    {
+    this->OrderDependentRPath
+      ->SetImplicitDirectories(this->ImplicitLinkDirs);
+    }
+
   // Initial state.
   this->HaveUserFlagItem = false;
 
@@ -374,6 +420,7 @@
 //----------------------------------------------------------------------------
 cmComputeLinkInformation::~cmComputeLinkInformation()
 {
+  delete this->OrderLinkerSearchPath;
   delete this->OrderRuntimeSearchPath;
   delete this->OrderDependentRPath;
 }
@@ -388,7 +435,7 @@
 //----------------------------------------------------------------------------
 std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
 {
-  return this->Directories;
+  return this->OrderLinkerSearchPath->GetOrderedDirectories();
 }
 
 //----------------------------------------------------------------------------
@@ -396,7 +443,7 @@
 {
   // If there is no separate linker runtime search flag (-rpath-link)
   // there is no reason to compute a string.
-  if(!this->OrderDependentRPath || this->RPathLinkFlag.empty())
+  if(!this->OrderDependentRPath)
     {
     return "";
     }
@@ -405,7 +452,7 @@
   std::string rpath_link;
   const char* sep = "";
   std::vector<std::string> const& dirs =
-    this->OrderDependentRPath->GetRuntimePath();
+    this->OrderDependentRPath->GetOrderedDirectories();
   for(std::vector<std::string>::const_iterator di = dirs.begin();
       di != dirs.end(); ++di)
     {
@@ -487,8 +534,8 @@
     this->SetCurrentLinkType(this->StartLinkType);
     }
 
-  // Compute the linker search path.
-  this->ComputeLinkerSearchDirectories();
+  // Finish setting up linker search directories.
+  this->FinishLinkerSearchDirectories();
 
   return true;
 }
@@ -637,19 +684,31 @@
     this->AddLibraryRuntimeInfo(lib);
     }
 
-  // Add the item to the separate dependent library search path if
-  // this platform wants one.
-  if(this->OrderDependentRPath)
+  // Check if we need to include the dependent shared library in other
+  // path ordering.
+  cmOrderDirectories* order = 0;
+  if(this->SharedDependencyMode == SharedDepModeLibDir &&
+     !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */)
+    {
+    // Add the item to the linker search path.
+    order = this->OrderLinkerSearchPath;
+    }
+  else if(this->SharedDependencyMode == SharedDepModeDir)
+    {
+    // Add the item to the separate dependent library search path.
+    order = this->OrderDependentRPath;
+    }
+  if(order)
     {
     if(tgt)
       {
       std::string soName = tgt->GetSOName(this->Config);
       const char* soname = soName.empty()? 0 : soName.c_str();
-      this->OrderDependentRPath->AddLibrary(lib, soname);
+      order->AddRuntimeLibrary(lib, soname);
       }
     else
       {
-      this->OrderDependentRPath->AddLibrary(lib);
+      order->AddRuntimeLibrary(lib);
       }
     }
 }
@@ -747,7 +806,8 @@
   // Create regex to remove any library extension.
   std::string reg("(.*)");
   reg += libext;
-  this->RemoveLibraryExtension.compile(reg.c_str());
+  this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions,
+                                                    reg);
 
   // Create a regex to match a library name.  Match index 1 will be
   // the prefix if it exists and empty otherwise.  Match index 2 will
@@ -913,18 +973,26 @@
     this->SetCurrentLinkType(LinkShared);
     }
 
-  // If this platform wants a flag before the full path, add it.
-  if(!this->LibLinkFileFlag.empty())
-    {
-    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);
     }
 
+  // Handle case of an imported shared library with no soname.
+  if(this->NoSONameUsesPath &&
+     target->IsImportedSharedLibWithoutSOName(this->Config))
+    {
+    this->AddSharedLibNoSOName(item);
+    return;
+    }
+
+  // If this platform wants a flag before the full path, add it.
+  if(!this->LibLinkFileFlag.empty())
+    {
+    this->Items.push_back(Item(this->LibLinkFileFlag, false));
+    }
+
   // Now add the full path to the library.
   this->Items.push_back(Item(item, true));
 }
@@ -938,6 +1006,12 @@
     return;
     }
 
+  // Check for case of shared library with no builtin soname.
+  if(this->NoSONameUsesPath && this->CheckSharedLibNoSOName(item))
+    {
+    return;
+    }
+
   // This is called to handle a link item that is a full path.
   // If the target is not a static library make sure the link type is
   // shared.  This is because dynamic-mode linking can handle both
@@ -959,11 +1033,11 @@
       }
     }
 
-  // Record the directory in which the library appears because CMake
-  // 2.4 in below added these as -L paths.
+  // For compatibility with CMake 2.4 include the item's directory in
+  // the linker search path.
   if(this->OldLinkDirMode)
     {
-    this->OldLinkDirs.push_back(cmSystemTools::GetFilenamePath(item));
+    this->OldLinkDirItems.push_back(item);
     }
 
   // If this platform wants a flag before the full path, add it.
@@ -1184,55 +1258,47 @@
 }
 
 //----------------------------------------------------------------------------
-void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
+bool cmComputeLinkInformation::CheckSharedLibNoSOName(std::string const& item)
 {
-  // Some search paths should never be emitted.
-  this->DirectoriesEmmitted = this->ImplicitLinkDirs;
-  this->DirectoriesEmmitted.insert("");
-
-  // Check if we need to include the runtime search path at link time.
-  std::string var = "CMAKE_SHARED_LIBRARY_LINK_";
-  var += this->LinkLanguage;
-  var += "_WITH_RUNTIME_PATH";
-  if(this->Makefile->IsOn(var.c_str()))
+  // This platform will use the path to a library as its soname if the
+  // library is given via path and was not built with an soname.  If
+  // this is a shared library that might be the case.  TODO: Check if
+  // the lib is a symlink to detect that it actually has an soname.
+  std::string file = cmSystemTools::GetFilenameName(item);
+  if(this->ExtractSharedLibraryName.find(file))
     {
-    // This platform requires the runtime library path for shared
-    // libraries to be specified at link time as -L paths.  It needs
-    // them so that transitive dependencies of the libraries linked
-    // may be found by the linker.
-    this->AddLinkerSearchDirectories(this->GetRuntimeSearchPath());
+    this->AddSharedLibNoSOName(item);
+    return true;
     }
+  return false;
+}
 
-  // Get the search path entries requested by the user.
-  this->AddLinkerSearchDirectories(this->Target->GetLinkDirectories());
-
-  // Support broken projects if necessary.
-  if(this->HaveUserFlagItem && this->OldLinkDirMode)
-    {
-    this->AddLinkerSearchDirectories(this->OldLinkDirs);
-    }
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddSharedLibNoSOName(std::string const& item)
+{
+  // We have a full path to a shared library with no soname.  We need
+  // to ask the linker to locate the item because otherwise the path
+  // we give to it will be embedded in the target linked.  Then at
+  // runtime the dynamic linker will search for the library using the
+  // path instead of just the name.
+  std::string file = cmSystemTools::GetFilenameName(item);
+  this->AddUserItem(file);
 
-  // If there is no separate linker runtime search flag (-rpath-link)
-  // and we have a search path for dependent libraries add it to the
-  // link directories.
-  if(this->OrderDependentRPath && this->RPathLinkFlag.empty())
-    {
-    this->AddLinkerSearchDirectories
-      (this->OrderDependentRPath->GetRuntimePath());
-    }
+  // Make sure the link directory ordering will find the library.
+  this->OrderLinkerSearchPath->AddLinkLibrary(item);
 }
 
 //----------------------------------------------------------------------------
-void
-cmComputeLinkInformation
-::AddLinkerSearchDirectories(std::vector<std::string> const& dirs)
+void cmComputeLinkInformation::FinishLinkerSearchDirectories()
 {
-  for(std::vector<std::string>::const_iterator i = dirs.begin();
-      i != dirs.end(); ++i)
+  // Support broken projects if necessary.
+  if(this->HaveUserFlagItem && this->OldLinkDirMode)
     {
-    if(this->DirectoriesEmmitted.insert(*i).second)
+    for(std::vector<std::string>::const_iterator
+          i = this->OldLinkDirItems.begin();
+        i != this->OldLinkDirItems.end(); ++i)
       {
-      this->Directories.push_back(*i);
+      this->OrderLinkerSearchPath->AddLinkLibrary(*i);
       }
     }
 }
@@ -1241,7 +1307,7 @@
 std::vector<std::string> const&
 cmComputeLinkInformation::GetRuntimeSearchPath()
 {
-  return this->OrderRuntimeSearchPath->GetRuntimePath();
+  return this->OrderRuntimeSearchPath->GetOrderedDirectories();
 }
 
 //----------------------------------------------------------------------------
@@ -1261,7 +1327,11 @@
   const char* soname = soName.empty()? 0 : soName.c_str();
 
   // Include this library in the runtime path ordering.
-  this->OrderRuntimeSearchPath->AddLibrary(fullPath, soname);
+  this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath, soname);
+  if(this->LinkWithRuntimePath)
+    {
+    this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath, soname);
+    }
 }
 
 //----------------------------------------------------------------------------
@@ -1289,7 +1359,11 @@
     }
 
   // Include this library in the runtime path ordering.
-  this->OrderRuntimeSearchPath->AddLibrary(fullPath);
+  this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
+  if(this->LinkWithRuntimePath)
+    {
+    this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
+    }
 }
 
 //----------------------------------------------------------------------------

--- NEW FILE: cmOrderDirectories.cxx ---
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile: cmOrderDirectories.cxx,v $
  Language:  C++
  Date:      $Date: 2008/02/21 16:41:11 $
  Version:   $Revision: 1.1 $

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "cmOrderDirectories.h"

#include "cmGlobalGenerator.h"
#include "cmSystemTools.h"

#include <assert.h>

#include <algorithm>

/*
Directory ordering computation.
  - Useful to compute a safe runtime library path order
  - Need runtime path for supporting INSTALL_RPATH_USE_LINK_PATH
  - Need runtime path at link time to pickup transitive link dependencies
    for shared libraries.
*/

//----------------------------------------------------------------------------
class cmOrderDirectoriesConstraint
{
public:
  cmOrderDirectoriesConstraint(cmOrderDirectories* od,
                               std::string const& file):
    OD(od), GlobalGenerator(od->GlobalGenerator)
    {
    this->FullPath = file;
    this->Directory = cmSystemTools::GetFilenamePath(file);
    this->FileName = cmSystemTools::GetFilenameName(file);
    }
  virtual ~cmOrderDirectoriesConstraint() {}

  void AddDirectory()
    {
    this->DirectoryIndex = this->OD->AddOriginalDirectory(this->Directory);
    }

  virtual void Report(std::ostream& e) = 0;

  void FindConflicts(unsigned int index)
    {
    for(unsigned int i=0; i < this->OD->OriginalDirectories.size(); ++i)
      {
      // Check if this directory conflicts with they entry.
      std::string const& dir = this->OD->OriginalDirectories[i];
      if(dir != this->Directory && this->FindConflict(dir))
        {
        // The library will be found in this directory but this is not
        // the directory named for it.  Add an entry to make sure the
        // desired directory comes before this one.
        cmOrderDirectories::ConflictPair p(this->DirectoryIndex, index);
        this->OD->ConflictGraph[i].push_back(p);
        }
      }
    }
protected:
  virtual bool FindConflict(std::string const& dir) = 0;

  bool FileMayConflict(std::string const& dir, std::string const& name);

  cmOrderDirectories* OD;
  cmGlobalGenerator* GlobalGenerator;

  // The location in which the item is supposed to be found.
  std::string FullPath;
  std::string Directory;
  std::string FileName;

  // The index assigned to the directory.
  int DirectoryIndex;
};

//----------------------------------------------------------------------------
bool cmOrderDirectoriesConstraint::FileMayConflict(std::string const& dir,
                                                   std::string const& name)
{
  // Check if the file will be built by cmake.
  std::set<cmStdString> const& files =
    (this->GlobalGenerator->GetDirectoryContent(dir, false));
  if(std::set<cmStdString>::const_iterator(files.find(name)) != files.end())
    {
    return true;
    }

  // Check if the file exists on disk and is not a symlink back to the
  // original file.
  std::string file = dir;
  file += "/";
  file += name;
  if(cmSystemTools::FileExists(file.c_str(), true) &&
     !cmSystemTools::SameFile(this->FullPath.c_str(), file.c_str()))
    {
    return true;
    }
  return false;
}

//----------------------------------------------------------------------------
class cmOrderDirectoriesConstraintSOName: public cmOrderDirectoriesConstraint
{
public:
  cmOrderDirectoriesConstraintSOName(cmOrderDirectories* od,
                                     std::string const& file,
                                     const char* soname):
    cmOrderDirectoriesConstraint(od, file), SOName(soname? soname : "")
    {
    }

  virtual void Report(std::ostream& e)
    {
    e << "runtime library [";
    if(this->SOName.empty())
      {
      e << this->FileName;
      }
    else
      {
      e << this->SOName;
      }
    e << "]";
    }

  virtual bool FindConflict(std::string const& dir);
private:
  // The soname of the shared library if it is known.
  std::string SOName;
};

//----------------------------------------------------------------------------
bool cmOrderDirectoriesConstraintSOName::FindConflict(std::string const& dir)
{
  // Determine which type of check to do.
  if(!this->SOName.empty())
    {
    // We have the library soname.  Check if it will be found.
    if(this->FileMayConflict(dir, this->SOName))
      {
      return true;
      }
    }
  else
    {
    // We do not have the soname.  Look for files in the directory
    // that may conflict.
    std::set<cmStdString> const& files =
      (this->GlobalGenerator
       ->GetDirectoryContent(dir, true));

    // Get the set of files that might conflict.  Since we do not
    // know the soname just look at all files that start with the
    // file name.  Usually the soname starts with the library name.
    // TODO: Check if the library is a symlink and guess the soname.
    std::string base = this->FileName;
    std::set<cmStdString>::const_iterator first = files.lower_bound(base);
    ++base[base.size()-1];
    std::set<cmStdString>::const_iterator last = files.upper_bound(base);
    bool found = false;
    for(std::set<cmStdString>::const_iterator fi = first; fi != last; ++fi)
      {
      return true;
      }
    }
  return false;
}

//----------------------------------------------------------------------------
class cmOrderDirectoriesConstraintLibrary: public cmOrderDirectoriesConstraint
{
public:
  cmOrderDirectoriesConstraintLibrary(cmOrderDirectories* od,
                                      std::string const& file):
    cmOrderDirectoriesConstraint(od, file)
    {
    }

  virtual void Report(std::ostream& e)
    {
    e << "link library [" << this->FileName << "]";
    }

  virtual bool FindConflict(std::string const& dir);
};

//----------------------------------------------------------------------------
bool cmOrderDirectoriesConstraintLibrary::FindConflict(std::string const& dir)
{
  // We have the library file name.  Check if it will be found.
  if(this->FileMayConflict(dir, this->FileName))
    {
    return true;
    }

  // Now check if the file exists with other extensions the linker
  // might consider.
  if(!this->OD->LinkExtensions.empty() &&
     this->OD->RemoveLibraryExtension.find(this->FileName))
    {
    cmStdString lib = this->OD->RemoveLibraryExtension.match(1);
    cmStdString ext = this->OD->RemoveLibraryExtension.match(2);
    for(std::vector<std::string>::iterator
          i = this->OD->LinkExtensions.begin();
        i != this->OD->LinkExtensions.end(); ++i)
      {
      if(*i != ext)
        {
        std::string fname = lib;
        fname += *i;
        if(this->FileMayConflict(dir, fname.c_str()))
          {
          return true;
          }
        }
      }
    }
  return false;
}

//----------------------------------------------------------------------------
cmOrderDirectories::cmOrderDirectories(cmGlobalGenerator* gg,
                                       const char* name,
                                       const char* purpose)
{
  this->GlobalGenerator = gg;
  this->Name = name;
  this->Purpose = purpose;
  this->Computed = false;
}

//----------------------------------------------------------------------------
cmOrderDirectories::~cmOrderDirectories()
{
  for(std::vector<cmOrderDirectoriesConstraint*>::iterator
        i = this->ConstraintEntries.begin();
      i != this->ConstraintEntries.end(); ++i)
    {
    delete *i;
    }
}

//----------------------------------------------------------------------------
std::vector<std::string> const& cmOrderDirectories::GetOrderedDirectories()
{
  if(!this->Computed)
    {
    this->Computed = true;
    this->CollectOriginalDirectories();
    this->FindConflicts();
    this->OrderDirectories();
    }
  return this->OrderedDirectories;
}

//----------------------------------------------------------------------------
void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath,
                                           const char* soname)
{
  // Add the runtime library at most once.
  if(this->EmmittedConstraintSOName.insert(fullPath).second)
    {
    // Avoid dealing with implicit directories.
    if(!this->ImplicitDirectories.empty())
      {
      std::string dir = cmSystemTools::GetFilenamePath(fullPath);
      if(this->ImplicitDirectories.find(dir) !=
         this->ImplicitDirectories.end())
        {
        return;
        }
      }

    // Construct the runtime information entry for this library.
    this->ConstraintEntries.push_back(
      new cmOrderDirectoriesConstraintSOName(this, fullPath, soname));
    }
  else
    {
    // This can happen if the same library is linked multiple times.
    // In that case the runtime information check need be done only
    // once anyway.  For shared libs we could add a check in AddItem
    // to not repeat them.
    }
}

//----------------------------------------------------------------------------
void cmOrderDirectories::AddLinkLibrary(std::string const& fullPath)
{
  // Link extension info is required for library constraints.
  assert(!this->LinkExtensions.empty());

  // Add the link library at most once.
  if(this->EmmittedConstraintLibrary.insert(fullPath).second)
    {
    // Avoid dealing with implicit directories.
    if(!this->ImplicitDirectories.empty())
      {
      std::string dir = cmSystemTools::GetFilenamePath(fullPath);
      if(this->ImplicitDirectories.find(dir) !=
         this->ImplicitDirectories.end())
        {
        return;
        }
      }

    // Construct the link library entry.
    this->ConstraintEntries.push_back(
      new cmOrderDirectoriesConstraintLibrary(this, fullPath));
    }
}

//----------------------------------------------------------------------------
void
cmOrderDirectories
::AddUserDirectories(std::vector<std::string> const& extra)
{
  this->UserDirectories.insert(this->UserDirectories.end(),
                               extra.begin(), extra.end());
}

//----------------------------------------------------------------------------
void
cmOrderDirectories
::SetImplicitDirectories(std::set<cmStdString> const& implicitDirs)
{
  this->ImplicitDirectories = implicitDirs;
}

//----------------------------------------------------------------------------
void
cmOrderDirectories
::SetLinkExtensionInfo(std::vector<std::string> const& linkExtensions,
                       std::string const& removeExtRegex)
{
  this->LinkExtensions = linkExtensions;
  this->RemoveLibraryExtension.compile(removeExtRegex.c_str());
}

//----------------------------------------------------------------------------
void cmOrderDirectories::CollectOriginalDirectories()
{
  // Add user directories specified for inclusion.  These should be
  // indexed first so their original order is preserved as much as
  // possible subject to the constraints.
  for(std::vector<std::string>::const_iterator
        di = this->UserDirectories.begin();
      di != this->UserDirectories.end(); ++di)
    {
    // Avoid dealing with implicit directories.
    if(this->ImplicitDirectories.find(*di) !=
       this->ImplicitDirectories.end())
      {
      continue;
      }

    // Skip the empty string.
    if(di->empty())
      {
      continue;
      }

    // Add this directory.
    this->AddOriginalDirectory(*di);
    }

  // Add directories containing constraints.
  for(unsigned int i=0; i < this->ConstraintEntries.size(); ++i)
    {
    this->ConstraintEntries[i]->AddDirectory();
    }
}

//----------------------------------------------------------------------------
int cmOrderDirectories::AddOriginalDirectory(std::string const& dir)
{
  // Add the runtime directory with a unique index.
  std::map<cmStdString, int>::iterator i =
    this->DirectoryIndex.find(dir);
  if(i == this->DirectoryIndex.end())
    {
    std::map<cmStdString, int>::value_type
      entry(dir, static_cast<int>(this->OriginalDirectories.size()));
    i = this->DirectoryIndex.insert(entry).first;
    this->OriginalDirectories.push_back(dir);
    }

  return i->second;
}

//----------------------------------------------------------------------------
struct cmOrderDirectoriesCompare
{
  typedef std::pair<int, int> ConflictPair;

  // The conflict pair is unique based on just the directory
  // (first).  The second element is only used for displaying
  // information about why the entry is present.
  bool operator()(ConflictPair const& l,
                  ConflictPair const& r)
    {
    return l.first == r.first;
    }
};

//----------------------------------------------------------------------------
void cmOrderDirectories::FindConflicts()
{
  // Allocate the conflict graph.
  this->ConflictGraph.resize(this->OriginalDirectories.size());
  this->DirectoryVisited.resize(this->OriginalDirectories.size(), 0);

  // Find directories conflicting with each entry.
  for(unsigned int i=0; i < this->ConstraintEntries.size(); ++i)
    {
    this->ConstraintEntries[i]->FindConflicts(i);
    }

  // Clean up the conflict graph representation.
  for(std::vector<ConflictList>::iterator
        i = this->ConflictGraph.begin();
      i != this->ConflictGraph.end(); ++i)
    {
    // Sort the outgoing edges for each graph node so that the
    // original order will be preserved as much as possible.
    std::sort(i->begin(), i->end());

    // Make the edge list unique so cycle detection will be reliable.
    ConflictList::iterator last =
      std::unique(i->begin(), i->end(), cmOrderDirectoriesCompare());
    i->erase(last, i->end());
    }
}

//----------------------------------------------------------------------------
void cmOrderDirectories::OrderDirectories()
{
  // Allow a cycle to be diagnosed once.
  this->CycleDiagnosed = false;
  this->WalkId = 0;

  // Iterate through the directories in the original order.
  for(unsigned int i=0; i < this->OriginalDirectories.size(); ++i)
    {
    // Start a new DFS from this node.
    ++this->WalkId;
    this->VisitDirectory(i);
    }
}

//----------------------------------------------------------------------------
void cmOrderDirectories::VisitDirectory(unsigned int i)
{
  // Skip nodes already visited.
  if(this->DirectoryVisited[i])
    {
    if(this->DirectoryVisited[i] == this->WalkId)
      {
      // We have reached a node previously visited on this DFS.
      // There is a cycle.
      this->DiagnoseCycle();
      }
    return;
    }

  // We are now visiting this node so mark it.
  this->DirectoryVisited[i] = this->WalkId;

  // Visit the neighbors of the node first.
  ConflictList const& clist = this->ConflictGraph[i];
  for(ConflictList::const_iterator j = clist.begin();
      j != clist.end(); ++j)
    {
    this->VisitDirectory(j->first);
    }

  // Now that all directories required to come before this one have
  // been emmitted, emit this directory.
  this->OrderedDirectories.push_back(this->OriginalDirectories[i]);
}

//----------------------------------------------------------------------------
void cmOrderDirectories::DiagnoseCycle()
{
  // Report the cycle at most once.
  if(this->CycleDiagnosed)
    {
    return;
    }
  this->CycleDiagnosed = true;

  // Construct the message.
  cmOStringStream e;
  e << "WARNING: Cannot generate a safe " << this->Purpose
    << " for target " << this->Name
    << " because there is a cycle in the constraint graph:\n";

  // Display the conflict graph.
  for(unsigned int i=0; i < this->ConflictGraph.size(); ++i)
    {
    ConflictList const& clist = this->ConflictGraph[i];
    e << "dir " << i << " is [" << this->OriginalDirectories[i] << "]\n";
    for(ConflictList::const_iterator j = clist.begin();
        j != clist.end(); ++j)
      {
      e << "  dir " << j->first << " must precede it due to ";
      this->ConstraintEntries[j->second]->Report(e);
      e << "\n";
      }
    }
  cmSystemTools::Message(e.str().c_str());
}

--- cmOrderRuntimeDirectories.cxx DELETED ---

Index: cmTarget.h
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmTarget.h,v
retrieving revision 1.106
retrieving revision 1.107
diff -u -d -r1.106 -r1.107
--- cmTarget.h	18 Feb 2008 21:38:34 -0000	1.106
+++ cmTarget.h	21 Feb 2008 16:41:11 -0000	1.107
@@ -281,6 +281,10 @@
   /** Get the soname of the target.  Allowed only for a shared library.  */
   std::string GetSOName(const char* config);
 
+  /** Test for special case of a third-party shared library that has
+      no soname at all.  */
+  bool IsImportedSharedLibWithoutSOName(const char* config);
+
   /** Get the full path to the target according to the settings in its
       makefile and the configuration type.  */
   std::string GetFullPath(const char* config=0, bool implib = false,
@@ -501,6 +505,7 @@
   // Cache import information from properties for each configuration.
   struct ImportInfo
   {
+    bool NoSOName;
     std::string Location;
     std::string SOName;
     std::string ImportLibrary;

Index: CMakeLists.txt
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/CMakeLists.txt,v
retrieving revision 1.394
retrieving revision 1.395
diff -u -d -r1.394 -r1.395
--- CMakeLists.txt	19 Feb 2008 19:33:43 -0000	1.394
+++ CMakeLists.txt	21 Feb 2008 16:41:10 -0000	1.395
@@ -167,8 +167,8 @@
   cmMakefileExecutableTargetGenerator.cxx
   cmMakefileLibraryTargetGenerator.cxx
   cmMakefileUtilityTargetGenerator.cxx
-  cmOrderRuntimeDirectories.cxx
-  cmOrderRuntimeDirectories.h
+  cmOrderDirectories.cxx
+  cmOrderDirectories.h
   cmProperty.cxx
   cmProperty.h
   cmPropertyDefinition.cxx

--- NEW FILE: cmOrderDirectories.h ---
/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile: cmOrderDirectories.h,v $
  Language:  C++
  Date:      $Date: 2008/02/21 16:41:11 $
  Version:   $Revision: 1.1 $

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef cmOrderDirectories_h
#define cmOrderDirectories_h

#include "cmStandardIncludes.h"

#include <cmsys/RegularExpression.hxx>

class cmGlobalGenerator;
class cmOrderDirectoriesConstraint;
class cmOrderDirectoriesConstraintLibrary;

/** \class cmOrderDirectories
 * \brief Compute a safe runtime path order for a set of shared libraries.
 */
class cmOrderDirectories
{
public:
  cmOrderDirectories(cmGlobalGenerator* gg, const char* name,
                     const char* purpose);
  ~cmOrderDirectories();
  void AddRuntimeLibrary(std::string const& fullPath, const char* soname = 0);
  void AddLinkLibrary(std::string const& fullPath);
  void AddUserDirectories(std::vector<std::string> const& extra);
  void SetImplicitDirectories(std::set<cmStdString> const& implicitDirs);
  void SetLinkExtensionInfo(std::vector<std::string> const& linkExtensions,
                            std::string const& removeExtRegex);

  std::vector<std::string> const& GetOrderedDirectories();
private:
  cmGlobalGenerator* GlobalGenerator;
  std::string Name;
  std::string Purpose;

  bool Computed;

  std::vector<std::string> OrderedDirectories;

  bool OrderedDirectoriesComputed;
  std::vector<cmOrderDirectoriesConstraint*> ConstraintEntries;
  std::vector<std::string> UserDirectories;
  cmsys::RegularExpression RemoveLibraryExtension;
  std::vector<std::string> LinkExtensions;
  std::set<cmStdString> ImplicitDirectories;
  std::set<cmStdString> EmmittedConstraintSOName;
  std::set<cmStdString> EmmittedConstraintLibrary;
  std::vector<std::string> OriginalDirectories;
  std::map<cmStdString, int> DirectoryIndex;
  std::vector<int> DirectoryVisited;
  void CollectOriginalDirectories();
  int AddOriginalDirectory(std::string const& dir);
  void FindConflicts();
  void OrderDirectories();
  void VisitDirectory(unsigned int i);
  void DiagnoseCycle();
  bool CycleDiagnosed;
  int WalkId;

  // Adjacency-list representation of runtime path ordering graph.
  // This maps from directory to those that must come *before* it.
  // Each entry that must come before is a pair.  The first element is
  // the index of the directory that must come first.  The second
  // element is the index of the runtime library that added the
  // constraint.
  typedef std::pair<int, int> ConflictPair;
  struct ConflictList: public std::vector<ConflictPair> {};
  std::vector<ConflictList> ConflictGraph;

  friend class cmOrderDirectoriesConstraint;
  friend class cmOrderDirectoriesConstraintLibrary;
};

#endif

--- cmOrderRuntimeDirectories.h DELETED ---

Index: cmTarget.cxx
===================================================================
RCS file: /cvsroot/CMake/CMake/Source/cmTarget.cxx,v
retrieving revision 1.198
retrieving revision 1.199
diff -u -d -r1.198 -r1.199
--- cmTarget.cxx	19 Feb 2008 14:09:46 -0000	1.198
+++ cmTarget.cxx	21 Feb 2008 16:41:11 -0000	1.199
@@ -2048,7 +2048,17 @@
     // Lookup the imported soname.
     if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
       {
-      return info->SOName;
+      if(info->NoSOName)
+        {
+        // The imported library has no builtin soname so the name
+        // searched at runtime will be just the filename.
+        return cmSystemTools::GetFilenameName(info->Location);
+        }
+      else
+        {
+        // Use the soname given if any.
+        return info->SOName;
+        }
       }
     else
       {
@@ -2069,6 +2079,19 @@
 }
 
 //----------------------------------------------------------------------------
+bool cmTarget::IsImportedSharedLibWithoutSOName(const char* config)
+{
+  if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY)
+    {
+    if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+      {
+      return info->NoSOName;
+      }
+    }
+  return false;
+}
+
+//----------------------------------------------------------------------------
 std::string cmTarget::NormalGetRealName(const char* config)
 {
   // This should not be called for imported targets.
@@ -3054,6 +3077,9 @@
   // properties.  The "IMPORTED_" namespace is reserved for properties
   // defined by the project exporting the target.
 
+  // Initialize members.
+  info.NoSOName = false;
+
   // Track the configuration-specific property suffix.
   std::string suffix = "_";
   suffix += desired_config;
@@ -3164,6 +3190,21 @@
       }
     }
 
+  // Get the "no-soname" mark.
+  if(this->GetType() == cmTarget::SHARED_LIBRARY)
+    {
+    std::string soProp = "IMPORTED_NO_SONAME";
+    soProp += suffix;
+    if(const char* config_no_soname = this->GetProperty(soProp.c_str()))
+      {
+      info.NoSOName = cmSystemTools::IsOn(config_no_soname);
+      }
+    else if(const char* no_soname = this->GetProperty("IMPORTED_NO_SONAME"))
+      {
+      info.NoSOName = cmSystemTools::IsOn(no_soname);
+      }
+    }
+
   // Get the import library.
   if(this->GetType() == cmTarget::SHARED_LIBRARY ||
      this->IsExecutableWithExports())



More information about the Cmake-commits mailing list