summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2008-02-21 16:41:11 (GMT)
committerBrad King <brad.king@kitware.com>2008-02-21 16:41:11 (GMT)
commitfd37a6ec3d31e65eed2dfa88246e86b8d0ab66ab (patch)
treee40d02f354785ea8c43e90f266cded73bba5f340
parent9f2f456e7db1f84cc6d10a64a8e515ad69afbe65 (diff)
downloadCMake-fd37a6ec3d31e65eed2dfa88246e86b8d0ab66ab.zip
CMake-fd37a6ec3d31e65eed2dfa88246e86b8d0ab66ab.tar.gz
CMake-fd37a6ec3d31e65eed2dfa88246e86b8d0ab66ab.tar.bz2
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
-rw-r--r--Modules/Platform/FreeBSD.cmake4
-rw-r--r--Modules/Platform/HP-UX.cmake4
-rw-r--r--Modules/Platform/Linux.cmake4
-rw-r--r--Modules/Platform/QNX.cmake4
-rw-r--r--Modules/Platform/SunOS.cmake4
-rw-r--r--Source/CMakeLists.txt4
-rw-r--r--Source/cmComputeLinkInformation.cxx224
-rw-r--r--Source/cmComputeLinkInformation.h27
-rw-r--r--Source/cmOrderDirectories.cxx524
-rw-r--r--Source/cmOrderDirectories.h88
-rw-r--r--Source/cmOrderRuntimeDirectories.cxx325
-rw-r--r--Source/cmOrderRuntimeDirectories.h88
-rw-r--r--Source/cmTarget.cxx43
-rw-r--r--Source/cmTarget.h5
-rwxr-xr-xbootstrap2
15 files changed, 845 insertions, 505 deletions
diff --git a/Modules/Platform/FreeBSD.cmake b/Modules/Platform/FreeBSD.cmake
index 299847b..e7b26ac 100644
--- a/Modules/Platform/FreeBSD.cmake
+++ b/Modules/Platform/FreeBSD.cmake
@@ -12,6 +12,10 @@ IF(EXISTS /usr/include/dlfcn.h)
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
ENDIF(EXISTS /usr/include/dlfcn.h)
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
# Initialize C link type selection flags. These flags are used when
# building a shared library, shared module, or executable that links
# to other libraries to select whether to use the static or shared
diff --git a/Modules/Platform/HP-UX.cmake b/Modules/Platform/HP-UX.cmake
index ae036b9..50dedc3 100644
--- a/Modules/Platform/HP-UX.cmake
+++ b/Modules/Platform/HP-UX.cmake
@@ -8,6 +8,10 @@ SET(CMAKE_FIND_LIBRARY_SUFFIXES ".sl" ".so" ".a")
SET(CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH 1)
SET(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
# fortran
IF(CMAKE_COMPILER_IS_GNUG77)
SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-fPIC") # -pic
diff --git a/Modules/Platform/Linux.cmake b/Modules/Platform/Linux.cmake
index 095eac6..eba4bb3 100644
--- a/Modules/Platform/Linux.cmake
+++ b/Modules/Platform/Linux.cmake
@@ -12,6 +12,10 @@ SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-soname,")
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
# Initialize C link type selection flags. These flags are used when
# building a shared library, shared module, or executable that links
# to other libraries to select whether to use the static or shared
diff --git a/Modules/Platform/QNX.cmake b/Modules/Platform/QNX.cmake
index f73997a..b48383a 100644
--- a/Modules/Platform/QNX.cmake
+++ b/Modules/Platform/QNX.cmake
@@ -19,6 +19,10 @@ SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
# Initialize C link type selection flags. These flags are used when
# building a shared library, shared module, or executable that links
# to other libraries to select whether to use the static or shared
diff --git a/Modules/Platform/SunOS.cmake b/Modules/Platform/SunOS.cmake
index f6c9d2e..9bd8b09 100644
--- a/Modules/Platform/SunOS.cmake
+++ b/Modules/Platform/SunOS.cmake
@@ -103,4 +103,6 @@ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
# in the -L path.
SET(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
-
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 20b2a3b..987e908 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -167,8 +167,8 @@ SET(SRCS
cmMakefileExecutableTargetGenerator.cxx
cmMakefileLibraryTargetGenerator.cxx
cmMakefileUtilityTargetGenerator.cxx
- cmOrderRuntimeDirectories.cxx
- cmOrderRuntimeDirectories.h
+ cmOrderDirectories.cxx
+ cmOrderDirectories.h
cmProperty.cxx
cmProperty.h
cmPropertyDefinition.cxx
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index dea08bc..1da512c 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -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 @@ libraries that are also linked need to be listed in -L paths.
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 @@ cmComputeLinkInformation
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 @@ cmComputeLinkInformation
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 @@ cmComputeLinkInformation
}
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 @@ cmComputeLinkInformation
}
}
+ // 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::~cmComputeLinkInformation()
{
+ delete this->OrderLinkerSearchPath;
delete this->OrderRuntimeSearchPath;
delete this->OrderDependentRPath;
}
@@ -388,7 +435,7 @@ cmComputeLinkInformation::GetItems()
//----------------------------------------------------------------------------
std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
{
- return this->Directories;
+ return this->OrderLinkerSearchPath->GetOrderedDirectories();
}
//----------------------------------------------------------------------------
@@ -396,7 +443,7 @@ std::string cmComputeLinkInformation::GetRPathLinkString()
{
// 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 cmComputeLinkInformation::GetRPathLinkString()
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 @@ bool cmComputeLinkInformation::Compute()
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 @@ void cmComputeLinkInformation::AddSharedDepItem(std::string const& item,
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 @@ void cmComputeLinkInformation::ComputeItemParserInfo()
// 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 @@ void cmComputeLinkInformation::AddTargetItem(std::string const& item,
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 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item)
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 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item)
}
}
- // 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::AddFrameworkPath(std::string const& p)
}
//----------------------------------------------------------------------------
-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 @@ cmComputeLinkInformation
std::vector<std::string> const&
cmComputeLinkInformation::GetRuntimeSearchPath()
{
- return this->OrderRuntimeSearchPath->GetRuntimePath();
+ return this->OrderRuntimeSearchPath->GetOrderedDirectories();
}
//----------------------------------------------------------------------------
@@ -1261,7 +1327,11 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
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 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath)
}
// Include this library in the runtime path ordering.
- this->OrderRuntimeSearchPath->AddLibrary(fullPath);
+ this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
+ if(this->LinkWithRuntimePath)
+ {
+ this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
+ }
}
//----------------------------------------------------------------------------
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index 0145e78..c0f8b5c 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -26,7 +26,7 @@ class cmGlobalGenerator;
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 @@ private:
// 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 @@ private:
std::string RuntimeSep;
std::string RuntimeAlways;
bool RuntimeUseChrpath;
+ bool NoSONameUsesPath;
+ bool LinkWithRuntimePath;
std::string RPathLinkFlag;
SharedDepMode SharedDependencyMode;
@@ -124,7 +127,6 @@ private:
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 @@ private:
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 @@ private:
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 @@ private:
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
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
new file mode 100644
index 0000000..7bc5dd6
--- /dev/null
+++ b/Source/cmOrderDirectories.cxx
@@ -0,0 +1,524 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ 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());
+}
diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h
new file mode 100644
index 0000000..00a5955
--- /dev/null
+++ b/Source/cmOrderDirectories.h
@@ -0,0 +1,88 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ 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
diff --git a/Source/cmOrderRuntimeDirectories.cxx b/Source/cmOrderRuntimeDirectories.cxx
deleted file mode 100644
index b0fe337..0000000
--- a/Source/cmOrderRuntimeDirectories.cxx
+++ /dev/null
@@ -1,325 +0,0 @@
-/*=========================================================================
-
- Program: CMake - Cross-Platform Makefile Generator
- Module: $RCSfile$
- Language: C++
- Date: $Date$
- Version: $Revision$
-
- 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 "cmOrderRuntimeDirectories.h"
-
-#include "cmGlobalGenerator.h"
-#include "cmSystemTools.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.
-*/
-
-//----------------------------------------------------------------------------
-cmOrderRuntimeDirectories::cmOrderRuntimeDirectories(cmGlobalGenerator* gg,
- const char* name,
- const char* purpose)
-{
- this->GlobalGenerator = gg;
- this->Name = name;
- this->Purpose = purpose;
- this->Computed = false;
-}
-
-//----------------------------------------------------------------------------
-std::vector<std::string> const& cmOrderRuntimeDirectories::GetRuntimePath()
-{
- if(!this->Computed)
- {
- this->Computed = true;
- this->CollectRuntimeDirectories();
- this->FindConflictingLibraries();
- this->OrderRuntimeSearchPath();
- }
- return this->RuntimeSearchPath;
-}
-
-//----------------------------------------------------------------------------
-void cmOrderRuntimeDirectories::AddLibrary(std::string const& fullPath,
- const char* soname)
-{
- // Add the runtime information at most once.
- if(this->LibraryRuntimeInfoEmmitted.insert(fullPath).second)
- {
- // Construct the runtime information entry for this library.
- LibraryRuntimeEntry entry;
- entry.FileName = cmSystemTools::GetFilenameName(fullPath);
- entry.SOName = soname? soname : "";
- entry.Directory = cmSystemTools::GetFilenamePath(fullPath);
- this->LibraryRuntimeInfo.push_back(entry);
- }
- 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
-cmOrderRuntimeDirectories
-::AddDirectories(std::vector<std::string> const& extra)
-{
- this->UserDirectories.insert(this->UserDirectories.end(),
- extra.begin(), extra.end());
-}
-
-//----------------------------------------------------------------------------
-void cmOrderRuntimeDirectories::CollectRuntimeDirectories()
-{
- // Get all directories that should be in the runtime search path.
-
- // Add directories containing libraries.
- for(std::vector<LibraryRuntimeEntry>::iterator
- ei = this->LibraryRuntimeInfo.begin();
- ei != this->LibraryRuntimeInfo.end(); ++ei)
- {
- ei->DirectoryIndex = this->AddRuntimeDirectory(ei->Directory);
- }
-
- // Add link directories specified for inclusion.
- for(std::vector<std::string>::const_iterator
- di = this->UserDirectories.begin();
- di != this->UserDirectories.end(); ++di)
- {
- this->AddRuntimeDirectory(*di);
- }
-}
-
-//----------------------------------------------------------------------------
-int cmOrderRuntimeDirectories::AddRuntimeDirectory(std::string const& dir)
-{
- // Add the runtime directory with a unique index.
- std::map<cmStdString, int>::iterator i =
- this->RuntimeDirectoryIndex.find(dir);
- if(i == this->RuntimeDirectoryIndex.end())
- {
- std::map<cmStdString, int>::value_type
- entry(dir, static_cast<int>(this->RuntimeDirectories.size()));
- i = this->RuntimeDirectoryIndex.insert(entry).first;
- this->RuntimeDirectories.push_back(dir);
- }
-
- return i->second;
-}
-
-//----------------------------------------------------------------------------
-struct cmOrderRuntimeDirectoriesCompare
-{
- typedef std::pair<int, int> RuntimeConflictPair;
-
- // 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()(RuntimeConflictPair const& l,
- RuntimeConflictPair const& r)
- {
- return l.first == r.first;
- }
-};
-
-//----------------------------------------------------------------------------
-void cmOrderRuntimeDirectories::FindConflictingLibraries()
-{
- // Allocate the conflict graph.
- this->RuntimeConflictGraph.resize(this->RuntimeDirectories.size());
- this->RuntimeDirectoryVisited.resize(this->RuntimeDirectories.size(), 0);
-
- // Find all runtime directories providing each library.
- for(unsigned int lri = 0; lri < this->LibraryRuntimeInfo.size(); ++lri)
- {
- this->FindDirectoriesForLib(lri);
- }
-
- // Clean up the conflict graph representation.
- for(std::vector<RuntimeConflictList>::iterator
- i = this->RuntimeConflictGraph.begin();
- i != this->RuntimeConflictGraph.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.
- RuntimeConflictList::iterator last =
- std::unique(i->begin(), i->end(), cmOrderRuntimeDirectoriesCompare());
- i->erase(last, i->end());
- }
-}
-
-//----------------------------------------------------------------------------
-void cmOrderRuntimeDirectories::FindDirectoriesForLib(unsigned int lri)
-{
- // Search through the runtime directories to find those providing
- // this library.
- LibraryRuntimeEntry& re = this->LibraryRuntimeInfo[lri];
- for(unsigned int i = 0; i < this->RuntimeDirectories.size(); ++i)
- {
- // Skip the directory that is supposed to provide the library.
- if(this->RuntimeDirectories[i] == re.Directory)
- {
- continue;
- }
-
- // Determine which type of check to do.
- if(!re.SOName.empty())
- {
- // We have the library soname. Check if it will be found.
- std::string file = this->RuntimeDirectories[i];
- file += "/";
- file += re.SOName;
- std::set<cmStdString> const& files =
- (this->GlobalGenerator
- ->GetDirectoryContent(this->RuntimeDirectories[i], false));
- if((std::set<cmStdString>::const_iterator(files.find(re.SOName)) !=
- files.end()) ||
- cmSystemTools::FileExists(file.c_str(), true))
- {
- // 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.
- RuntimeConflictPair p(re.DirectoryIndex, lri);
- this->RuntimeConflictGraph[i].push_back(p);
- }
- }
- else
- {
- // We do not have the soname. Look for files in the directory
- // that may conflict.
- std::set<cmStdString> const& files =
- (this->GlobalGenerator
- ->GetDirectoryContent(this->RuntimeDirectories[i], 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.
- std::string base = re.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;
- !found && fi != last; ++fi)
- {
- found = true;
- }
-
- if(found)
- {
- // The library may 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.
- RuntimeConflictPair p(re.DirectoryIndex, lri);
- this->RuntimeConflictGraph[i].push_back(p);
- }
- }
- }
-}
-
-//----------------------------------------------------------------------------
-void cmOrderRuntimeDirectories::OrderRuntimeSearchPath()
-{
- // 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->RuntimeDirectories.size(); ++i)
- {
- // Start a new DFS from this node.
- ++this->WalkId;
- this->VisitRuntimeDirectory(i);
- }
-}
-
-//----------------------------------------------------------------------------
-void cmOrderRuntimeDirectories::VisitRuntimeDirectory(unsigned int i)
-{
- // Skip nodes already visited.
- if(this->RuntimeDirectoryVisited[i])
- {
- if(this->RuntimeDirectoryVisited[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->RuntimeDirectoryVisited[i] = this->WalkId;
-
- // Visit the neighbors of the node first.
- RuntimeConflictList const& clist = this->RuntimeConflictGraph[i];
- for(RuntimeConflictList::const_iterator j = clist.begin();
- j != clist.end(); ++j)
- {
- this->VisitRuntimeDirectory(j->first);
- }
-
- // Now that all directories required to come before this one have
- // been emmitted, emit this directory.
- this->RuntimeSearchPath.push_back(this->RuntimeDirectories[i]);
-}
-
-//----------------------------------------------------------------------------
-void cmOrderRuntimeDirectories::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->RuntimeConflictGraph.size(); ++i)
- {
- RuntimeConflictList const& clist = this->RuntimeConflictGraph[i];
- e << "dir " << i << " is [" << this->RuntimeDirectories[i] << "]\n";
- for(RuntimeConflictList::const_iterator j = clist.begin();
- j != clist.end(); ++j)
- {
- e << " dir " << j->first << " must precede it due to [";
- LibraryRuntimeEntry const& re = this->LibraryRuntimeInfo[j->second];
- if(re.SOName.empty())
- {
- e << re.FileName;
- }
- else
- {
- e << re.SOName;
- }
- e << "]\n";
- }
- }
- cmSystemTools::Message(e.str().c_str());
-}
diff --git a/Source/cmOrderRuntimeDirectories.h b/Source/cmOrderRuntimeDirectories.h
deleted file mode 100644
index d249f8f..0000000
--- a/Source/cmOrderRuntimeDirectories.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*=========================================================================
-
- Program: CMake - Cross-Platform Makefile Generator
- Module: $RCSfile$
- Language: C++
- Date: $Date$
- Version: $Revision$
-
- 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 cmOrderRuntimeDirectories_h
-#define cmOrderRuntimeDirectories_h
-
-#include "cmStandardIncludes.h"
-
-class cmGlobalGenerator;
-
-/** \class cmOrderRuntimeDirectories
- * \brief Compute a safe runtime path order for a set of shared libraries.
- */
-class cmOrderRuntimeDirectories
-{
-public:
- cmOrderRuntimeDirectories(cmGlobalGenerator* gg, const char* name,
- const char* purpose);
- void AddLibrary(std::string const& fullPath, const char* soname = 0);
- void AddDirectories(std::vector<std::string> const& extra);
-
- std::vector<std::string> const& GetRuntimePath();
-private:
- cmGlobalGenerator* GlobalGenerator;
- std::string Name;
- std::string Purpose;
-
- bool Computed;
-
- std::vector<std::string> RuntimeSearchPath;
-
- // Runtime path computation.
- struct LibraryRuntimeEntry
- {
- // The file name of the library.
- std::string FileName;
-
- // The soname of the shared library if it is known.
- std::string SOName;
-
- // The directory in which the library is supposed to be found.
- std::string Directory;
-
- // The index assigned to the directory.
- int DirectoryIndex;
- };
- bool RuntimeSearchPathComputed;
- std::vector<LibraryRuntimeEntry> LibraryRuntimeInfo;
- std::vector<std::string> UserDirectories;
- std::set<cmStdString> LibraryRuntimeInfoEmmitted;
- std::vector<std::string> RuntimeDirectories;
- std::map<cmStdString, int> RuntimeDirectoryIndex;
- std::vector<int> RuntimeDirectoryVisited;
- void CollectRuntimeDirectories();
- int AddRuntimeDirectory(std::string const& dir);
- void FindConflictingLibraries();
- void FindDirectoriesForLib(unsigned int lri);
- void OrderRuntimeSearchPath();
- void VisitRuntimeDirectory(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> RuntimeConflictPair;
- struct RuntimeConflictList: public std::vector<RuntimeConflictPair> {};
- std::vector<RuntimeConflictList> RuntimeConflictGraph;
-};
-
-#endif
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 4e3a345..3da4627 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -2048,7 +2048,17 @@ std::string cmTarget::GetSOName(const char* config)
// 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 @@ std::string cmTarget::GetSOName(const char* config)
}
//----------------------------------------------------------------------------
+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 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
// 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 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
}
}
+ // 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())
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index ad5a815..95c49da 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -281,6 +281,10 @@ public:
/** 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 @@ private:
// Cache import information from properties for each configuration.
struct ImportInfo
{
+ bool NoSOName;
std::string Location;
std::string SOName;
std::string ImportLibrary;
diff --git a/bootstrap b/bootstrap
index c14c4e0..40199ad 100755
--- a/bootstrap
+++ b/bootstrap
@@ -175,7 +175,7 @@ CMAKE_CXX_SOURCES="\
cmListFileCache \
cmComputeLinkDepends \
cmComputeLinkInformation \
- cmOrderRuntimeDirectories \
+ cmOrderDirectories \
cmComputeTargetDepends \
cmComputeComponentGraph \
cmExprLexer \