summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/CMakeCInformation.cmake4
-rw-r--r--Modules/CMakeCXXInformation.cmake8
-rw-r--r--Modules/CMakeFortranInformation.cmake8
-rw-r--r--Modules/Platform/Darwin.cmake2
-rw-r--r--Modules/Platform/Linux.cmake1
-rw-r--r--Modules/Platform/QNX.cmake1
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/cmComputeLinkDepends.cxx8
-rw-r--r--Source/cmComputeLinkInformation.cxx544
-rw-r--r--Source/cmComputeLinkInformation.h53
-rw-r--r--Source/cmDocumentVariables.cxx9
-rw-r--r--Source/cmExportBuildFileGenerator.cxx12
-rw-r--r--Source/cmExportBuildFileGenerator.h3
-rw-r--r--Source/cmExportFileGenerator.cxx2
-rw-r--r--Source/cmExportFileGenerator.h3
-rw-r--r--Source/cmExportInstallFileGenerator.cxx12
-rw-r--r--Source/cmExportInstallFileGenerator.h3
-rw-r--r--Source/cmLocalGenerator.cxx9
-rw-r--r--Source/cmOrderRuntimeDirectories.cxx325
-rw-r--r--Source/cmOrderRuntimeDirectories.h88
-rw-r--r--Source/cmTarget.cxx6
-rwxr-xr-xbootstrap1
22 files changed, 719 insertions, 385 deletions
diff --git a/Modules/CMakeCInformation.cmake b/Modules/CMakeCInformation.cmake
index f6d647e..77df12e 100644
--- a/Modules/CMakeCInformation.cmake
+++ b/Modules/CMakeCInformation.cmake
@@ -157,6 +157,10 @@ IF(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP)
SET(CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP)
+IF(NOT CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG)
+ SET(CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
+ENDIF(NOT CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG)
+
MARK_AS_ADVANCED(
CMAKE_C_FLAGS
CMAKE_C_FLAGS_DEBUG
diff --git a/Modules/CMakeCXXInformation.cmake b/Modules/CMakeCXXInformation.cmake
index 9fb5f1a..6cd2ec7 100644
--- a/Modules/CMakeCXXInformation.cmake
+++ b/Modules/CMakeCXXInformation.cmake
@@ -84,6 +84,10 @@ IF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP)
SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
ENDIF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP)
+IF(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG)
+ SET(CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
+ENDIF(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG)
+
IF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG)
SET(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG)
@@ -92,6 +96,10 @@ IF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP)
SET(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP)
+IF(NOT CMAKE_EXECUTABLE_RPATH_LINK_CXX_FLAG)
+ SET(CMAKE_EXECUTABLE_RPATH_LINK_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG})
+ENDIF(NOT CMAKE_EXECUTABLE_RPATH_LINK_CXX_FLAG)
+
IF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH)
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
ENDIF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH)
diff --git a/Modules/CMakeFortranInformation.cmake b/Modules/CMakeFortranInformation.cmake
index 93d2937..93d58b8 100644
--- a/Modules/CMakeFortranInformation.cmake
+++ b/Modules/CMakeFortranInformation.cmake
@@ -59,6 +59,10 @@ IF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP)
SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
ENDIF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP)
+IF(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG)
+ SET(CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
+ENDIF(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG)
+
# repeat for modules
IF(NOT CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS)
SET(CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS ${CMAKE_SHARED_MODULE_CREATE_C_FLAGS})
@@ -84,6 +88,10 @@ IF(NOT CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP)
SET(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP)
+IF(NOT CMAKE_EXECUTABLE_RPATH_LINK_Fortran_FLAG)
+ SET(CMAKE_EXECUTABLE_RPATH_LINK_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG})
+ENDIF(NOT CMAKE_EXECUTABLE_RPATH_LINK_Fortran_FLAG)
+
IF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH)
SET(CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
ENDIF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH)
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index 5b497d6..ce306b0 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -107,7 +107,7 @@ ENDIF(XCODE)
# with -isysroot (for universal binaries), the linker always looks for
# dependent libraries under the sysroot. Listing them on the link
# line works around the problem.
-SET(CMAKE_DEPENDENT_SHARED_LIBRARY_MODE "LINK")
+SET(CMAKE_LINK_DEPENDENT_LIBRARY_FILES 1)
SET(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
diff --git a/Modules/Platform/Linux.cmake b/Modules/Platform/Linux.cmake
index 85178ce..095eac6 100644
--- a/Modules/Platform/Linux.cmake
+++ b/Modules/Platform/Linux.cmake
@@ -5,6 +5,7 @@ SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-rdynamic")
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+SET(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-soname,")
diff --git a/Modules/Platform/QNX.cmake b/Modules/Platform/QNX.cmake
index e706a59..f73997a 100644
--- a/Modules/Platform/QNX.cmake
+++ b/Modules/Platform/QNX.cmake
@@ -13,6 +13,7 @@ SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS "")
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+SET(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 9608224..a73f511 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -161,6 +161,8 @@ SET(SRCS
cmMakefileExecutableTargetGenerator.cxx
cmMakefileLibraryTargetGenerator.cxx
cmMakefileUtilityTargetGenerator.cxx
+ cmOrderRuntimeDirectories.cxx
+ cmOrderRuntimeDirectories.h
cmProperty.cxx
cmProperty.h
cmPropertyDefinition.cxx
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index e49312e..cfcfe24 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -123,6 +123,14 @@ integer index with each link item. When the graph is built outgoing
edges are sorted by this index. This preserves the original link
order as much as possible subject to the dependencies.
+After the initial exploration of the link interface tree, any
+transitive (dependent) shared libraries that were encountered and not
+included in the interface are processed in their own BFS. This BFS
+follows only the dependent library lists and not the link interfaces.
+They are added to the link items with a mark indicating that the are
+transitive dependencies. Then cmComputeLinkInformation deals with
+them on a per-platform basis.
+
*/
//----------------------------------------------------------------------------
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index e7d83b0..b079f9d 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -17,14 +17,13 @@
#include "cmComputeLinkInformation.h"
#include "cmComputeLinkDepends.h"
+#include "cmOrderRuntimeDirectories.h"
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmTarget.h"
-#include <algorithm>
-
#include <ctype.h>
/*
@@ -150,6 +149,68 @@ ld: 92453-07 linker ld HP Itanium(R) B.12.41 IPF/IPF
or SHLIB_PATH, in searching for shared libraries. This changes
the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
RPATH (embedded path).
+
+------------------------------------------------------------------------------
+Notes about dependent (transitive) shared libraries:
+
+On non-Windows systems shared libraries may have transitive
+dependencies. In order to support LINK_INTERFACE_LIBRARIES we must
+support linking to a shared library without listing all the libraries
+to which it links. Some linkers want to be able to find the
+transitive dependencies (dependent libraries) of shared libraries
+listed on the command line.
+
+ - On Windows, DLLs are not directly linked, and the import libraries
+ have no transitive dependencies.
+
+ - On Mac, we need to actually list the transitive dependencies.
+ Otherwise when using -isysroot for universal binaries it cannot
+ find the dependent libraries. Listing them on the command line
+ tells the linker where to find them, but unfortunately also links
+ the library.
+
+ - On HP-UX, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths even if the dependent libraries
+ are given on the link line.
+
+ - On AIX the transitive dependencies are not needed.
+
+ - On SGI, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths if they are not given on the link
+ line. Transitive linking can be disabled using the options
+
+ -no_transitive_link -Wl,-no_transitive_link
+
+ which disable it. Both options must be given when invoking the
+ linker through the compiler.
+
+ - On Sun, the linker wants to find the transitive dependencies of
+ shared libraries in the -L paths if they are not given on the link
+ line.
+
+ - On Linux, FreeBSD, and QNX:
+
+ The linker wants to find the transitive dependencies of shared
+ libraries in the "-rpath-link" paths option if they have not been
+ given on the link line. The option is like rpath but just for
+ link time:
+
+ -Wl,-rpath-link,"/path1:/path2"
+
+For -rpath-link, we need a separate runtime path ordering pass
+including just the dependent libraries that are not linked.
+
+For -L paths on non-HP, we can do the same thing as with rpath-link
+but put the results in -L paths. The paths should be listed at the
+end to avoid conflicting with user search paths (?).
+
+For -L paths on HP, we should do a runtime path ordering pass with
+all libraries, both linked and non-linked. Even dependent
+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.
+
*/
//----------------------------------------------------------------------------
@@ -165,6 +226,12 @@ cmComputeLinkInformation
// The configuration being linked.
this->Config = config;
+ // Allocate internals.
+ this->OrderRuntimeSearchPath =
+ new cmOrderRuntimeDirectories(this->GlobalGenerator, target->GetName(),
+ "runtime path");
+ this->OrderDependentRPath = 0;
+
// Get the language used for linking this target.
this->LinkLanguage =
this->Target->GetLinkerLanguage(this->GlobalGenerator);
@@ -204,15 +271,11 @@ cmComputeLinkInformation
this->RuntimeUseChrpath = false;
if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
{
+ const char* tType =
+ ((this->Target->GetType() == cmTarget::EXECUTABLE)?
+ "EXECUTABLE" : "SHARED_LIBRARY");
std::string rtVar = "CMAKE_";
- if(this->Target->GetType() == cmTarget::EXECUTABLE)
- {
- rtVar += "EXECUTABLE";
- }
- else
- {
- rtVar += "SHARED_LIBRARY";
- }
+ rtVar += tType;
rtVar += "_RUNTIME_";
rtVar += this->LinkLanguage;
rtVar += "_FLAG";
@@ -223,6 +286,14 @@ cmComputeLinkInformation
(this->Makefile->
GetSafeDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
this->RuntimeUseChrpath = this->Target->IsChrpathUsed();
+
+ // Get options needed to help find dependent libraries.
+ std::string rlVar = "CMAKE_";
+ rlVar += tType;
+ rlVar += "_RPATH_LINK_";
+ rlVar += this->LinkLanguage;
+ rlVar += "_FLAG";
+ this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar.c_str());
}
// Get link type information.
@@ -236,17 +307,23 @@ cmComputeLinkInformation
// Choose a mode for dealing with shared library dependencies.
this->SharedDependencyMode = SharedDepModeNone;
- if(const char* mode =
- this->Makefile->GetDefinition("CMAKE_DEPENDENT_SHARED_LIBRARY_MODE"))
+ if(this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES"))
{
- if(strcmp(mode, "LINK") == 0)
- {
- this->SharedDependencyMode = SharedDepModeLink;
- }
- else if(strcmp(mode, "DIR") == 0)
- {
- this->SharedDependencyMode = SharedDepModeDir;
- }
+ this->SharedDependencyMode = SharedDepModeLink;
+ }
+ else if(this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS"))
+ {
+ this->SharedDependencyMode = SharedDepModeDir;
+ }
+ else if(!this->RPathLinkFlag.empty())
+ {
+ this->SharedDependencyMode = SharedDepModeDir;
+ }
+ if(this->SharedDependencyMode == SharedDepModeDir)
+ {
+ this->OrderDependentRPath =
+ new cmOrderRuntimeDirectories(this->GlobalGenerator, target->GetName(),
+ "dependent library path");
}
// Get the implicit link directories for this platform.
@@ -265,7 +342,6 @@ cmComputeLinkInformation
}
// Initial state.
- this->RuntimeSearchPathComputed = false;
this->HaveUserFlagItem = false;
// Decide whether to enable compatible library search path mode.
@@ -289,6 +365,13 @@ cmComputeLinkInformation
}
//----------------------------------------------------------------------------
+cmComputeLinkInformation::~cmComputeLinkInformation()
+{
+ delete this->OrderRuntimeSearchPath;
+ delete this->OrderDependentRPath;
+}
+
+//----------------------------------------------------------------------------
cmComputeLinkInformation::ItemVector const&
cmComputeLinkInformation::GetItems()
{
@@ -302,6 +385,31 @@ std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
}
//----------------------------------------------------------------------------
+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())
+ {
+ return "";
+ }
+
+ // Construct the linker runtime search path.
+ std::string rpath_link;
+ const char* sep = "";
+ std::vector<std::string> const& dirs =
+ this->OrderDependentRPath->GetRuntimePath();
+ for(std::vector<std::string>::const_iterator di = dirs.begin();
+ di != dirs.end(); ++di)
+ {
+ rpath_link += sep;
+ sep = ":";
+ rpath_link += *di;
+ }
+ return rpath_link;
+}
+
+//----------------------------------------------------------------------------
std::vector<std::string> const& cmComputeLinkInformation::GetDepends()
{
return this->Depends;
@@ -350,7 +458,14 @@ bool cmComputeLinkInformation::Compute()
lei = linkEntries.begin();
lei != linkEntries.end(); ++lei)
{
- this->AddItem(lei->Item, lei->Target, lei->IsSharedDep);
+ if(lei->IsSharedDep)
+ {
+ this->AddSharedDepItem(lei->Item, lei->Target);
+ }
+ else
+ {
+ this->AddItem(lei->Item, lei->Target);
+ }
}
// Restore the target link type so the correct system runtime
@@ -372,15 +487,8 @@ bool cmComputeLinkInformation::Compute()
}
//----------------------------------------------------------------------------
-void cmComputeLinkInformation::AddItem(std::string const& item,
- cmTarget* tgt, bool isSharedDep)
+void cmComputeLinkInformation::AddItem(std::string const& item, cmTarget* tgt)
{
- // If dropping shared library dependencies, ignore them.
- if(isSharedDep && this->SharedDependencyMode == SharedDepModeNone)
- {
- return;
- }
-
// Compute the proper name to use to link this library.
const char* config = this->Config;
bool impexe = (tgt && tgt->IsExecutableWithExports());
@@ -416,14 +524,6 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
(this->UseImportLibrary &&
(impexe || tgt->GetType() == cmTarget::SHARED_LIBRARY));
- // Handle shared dependencies in directory mode.
- if(isSharedDep && this->SharedDependencyMode == SharedDepModeDir)
- {
- std::string dir = tgt->GetDirectory(config, implib);
- this->SharedDependencyDirectories.push_back(dir);
- return;
- }
-
// Pass the full path to the target file.
std::string lib = tgt->GetFullPath(config, implib);
this->Depends.push_back(lib);
@@ -434,7 +534,6 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
// link.
std::string fw = tgt->GetDirectory(config, implib);
this->AddFrameworkItem(fw);
- this->SharedLibrariesLinked.insert(tgt);
}
else
{
@@ -470,6 +569,84 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
}
//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddSharedDepItem(std::string const& item,
+ cmTarget* tgt)
+{
+ // If dropping shared library dependencies, ignore them.
+ if(this->SharedDependencyMode == SharedDepModeNone)
+ {
+ return;
+ }
+
+ // The user may have incorrectly named an item. Skip items that are
+ // not full paths to shared libraries.
+ if(tgt)
+ {
+ // The target will provide a full path. Make sure it is a shared
+ // library.
+ if(tgt->GetType() != cmTarget::SHARED_LIBRARY)
+ {
+ return;
+ }
+ }
+ else
+ {
+ // Skip items that are not full paths. We will not be able to
+ // reliably specify them.
+ if(!cmSystemTools::FileIsFullPath(item.c_str()))
+ {
+ return;
+ }
+
+ // Get the name of the library from the file name.
+ std::string file = cmSystemTools::GetFilenameName(item);
+ if(!this->ExtractSharedLibraryName.find(file.c_str()))
+ {
+ // This is not the name of a shared library.
+ return;
+ }
+ }
+
+ // If in linking mode, just link to the shared library.
+ if(this->SharedDependencyMode == SharedDepModeLink)
+ {
+ this->AddItem(item, tgt);
+ return;
+ }
+
+ // Get a full path to the dependent shared library.
+ // Add it to the runtime path computation so that the target being
+ // linked will be able to find it.
+ std::string lib;
+ if(tgt)
+ {
+ lib = tgt->GetFullPath(this->Config, this->UseImportLibrary);
+ this->AddLibraryRuntimeInfo(lib, tgt);
+ }
+ else
+ {
+ lib = item;
+ this->AddLibraryRuntimeInfo(lib);
+ }
+
+ // Add the item to the separate dependent library search path if
+ // this platform wants one.
+ if(this->OrderDependentRPath)
+ {
+ if(tgt)
+ {
+ std::string soName = tgt->GetSOName(this->Config);
+ const char* soname = soName.empty()? 0 : soName.c_str();
+ this->OrderDependentRPath->AddLibrary(lib, soname);
+ }
+ else
+ {
+ this->OrderDependentRPath->AddLibrary(lib);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
void cmComputeLinkInformation::ComputeLinkTypeInfo()
{
// First assume we cannot do link type stuff.
@@ -1022,17 +1199,14 @@ void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
this->AddLinkerSearchDirectories(this->OldLinkDirs);
}
- // Help the linker find dependent shared libraries.
- if(this->SharedDependencyMode == SharedDepModeDir)
+ // 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())
{
- // TODO: These directories should probably be added to the runtime
- // path ordering analysis. However they are a bit different.
- // They should be placed both on the -L path and in the rpath.
- // The link-with-runtime-path feature above should be replaced by
- // this.
- this->AddLinkerSearchDirectories(this->SharedDependencyDirectories);
+ this->AddLinkerSearchDirectories
+ (this->OrderDependentRPath->GetRuntimePath());
}
-
}
//----------------------------------------------------------------------------
@@ -1054,23 +1228,9 @@ cmComputeLinkInformation
std::vector<std::string> const&
cmComputeLinkInformation::GetRuntimeSearchPath()
{
- if(!this->RuntimeSearchPathComputed)
- {
- this->RuntimeSearchPathComputed = true;
- this->CollectRuntimeDirectories();
- this->FindConflictingLibraries();
- this->OrderRuntimeSearchPath();
- }
- return this->RuntimeSearchPath;
+ return this->OrderRuntimeSearchPath->GetRuntimePath();
}
-//============================================================================
-// 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 (in future when we do not always add them).
-
//----------------------------------------------------------------------------
void
cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
@@ -1104,262 +1264,8 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
return;
}
- // 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 cmComputeLinkInformation::CollectRuntimeDirectories()
-{
- // Get all directories that should be in the runtime search path.
-
- // Add directories containing libraries linked with full path.
- 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 the target.
- std::vector<std::string> const& dirs = this->Target->GetLinkDirectories();
- for(std::vector<std::string>::const_iterator di = dirs.begin();
- di != dirs.end(); ++di)
- {
- this->AddRuntimeDirectory(*di);
- }
-}
-
-//----------------------------------------------------------------------------
-int cmComputeLinkInformation::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 cmCLIRuntimeConflictCompare
-{
- 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 cmComputeLinkInformation::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(), cmCLIRuntimeConflictCompare());
- i->erase(last, i->end());
- }
-}
-
-//----------------------------------------------------------------------------
-void cmComputeLinkInformation::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 cmComputeLinkInformation::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 cmComputeLinkInformation::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 cmComputeLinkInformation::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 runtime path for target "
- << this->Target->GetName()
- << " 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());
+ // Include this library in the runtime path ordering.
+ this->OrderRuntimeSearchPath->AddLibrary(fullPath, soname);
}
//----------------------------------------------------------------------------
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index 2bbe05d..c5f3778 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -25,6 +25,7 @@ class cmGlobalGenerator;
class cmLocalGenerator;
class cmMakefile;
class cmTarget;
+class cmOrderRuntimeDirectories;
/** \class cmComputeLinkInformation
* \brief Compute link information for a target in one configuration.
@@ -33,6 +34,7 @@ class cmComputeLinkInformation
{
public:
cmComputeLinkInformation(cmTarget* target, const char* config);
+ ~cmComputeLinkInformation();
bool Compute();
struct Item
@@ -57,8 +59,12 @@ public:
std::string GetChrpathString();
std::string GetChrpathTool();
std::set<cmTarget*> const& GetSharedLibrariesLinked();
+
+ std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }
+ std::string GetRPathLinkString();
private:
- void AddItem(std::string const& item, cmTarget* tgt, bool isSharedDep);
+ void AddItem(std::string const& item, cmTarget* tgt);
+ void AddSharedDepItem(std::string const& item, cmTarget* tgt);
// Output information.
ItemVector Items;
@@ -96,6 +102,7 @@ private:
std::string RuntimeSep;
std::string RuntimeAlways;
bool RuntimeUseChrpath;
+ std::string RPathLinkFlag;
SharedDepMode SharedDependencyMode;
// Link type adjustment.
@@ -143,7 +150,6 @@ private:
void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
std::set<cmStdString> DirectoriesEmmitted;
std::set<cmStdString> ImplicitLinkDirs;
- std::vector<std::string> SharedDependencyDirectories;
// Linker search path compatibility mode.
std::vector<std::string> OldLinkDirs;
@@ -151,48 +157,13 @@ private:
bool HaveUserFlagItem;
// 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::set<cmStdString> LibraryRuntimeInfoEmmitted;
- std::vector<std::string> RuntimeDirectories;
- std::map<cmStdString, int> RuntimeDirectoryIndex;
- std::vector<int> RuntimeDirectoryVisited;
+ cmOrderRuntimeDirectories* OrderRuntimeSearchPath;
void AddLibraryRuntimeInfo(std::string const& fullPath, cmTarget* target);
void AddLibraryRuntimeInfo(std::string const& fullPath,
const char* soname = 0);
- 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;
+
+ // Dependent library path computation.
+ cmOrderRuntimeDirectories* OrderDependentRPath;
};
#endif
diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx
index e7af505..c70ddea 100644
--- a/Source/cmDocumentVariables.cxx
+++ b/Source/cmDocumentVariables.cxx
@@ -1086,10 +1086,14 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_SHARED_LIBRARY_RUNTIME_<LANG>_FLAG_SEP",
cmProperty::VARIABLE,0,0);
+ cm->DefineProperty("CMAKE_SHARED_LIBRARY_RPATH_LINK_<LANG>_FLAG",
+ cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_EXECUTABLE_RUNTIME_<LANG>_FLAG",
cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_EXECUTABLE_RUNTIME_<LANG>_FLAG_SEP",
cmProperty::VARIABLE,0,0);
+ cm->DefineProperty("CMAKE_EXECUTABLE_RPATH_LINK_<LANG>_FLAG",
+ cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH",
cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS",
@@ -1104,7 +1108,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_SHARED_MODULE_RUNTIME_<LANG>_FLAG_SEP",
cmProperty::VARIABLE,0,0);
- cm->DefineProperty("CMAKE_DEPENDENT_SHARED_LIBRARY_MODE",
+ cm->DefineProperty("CMAKE_LINK_DEPENDENT_LIBRARY_FILES",
+ cmProperty::VARIABLE,0,0);
+ cm->DefineProperty("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS",
cmProperty::VARIABLE,0,0);
-
}
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 618cd19..6506254 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -122,7 +122,8 @@ cmExportBuildFileGenerator
//----------------------------------------------------------------------------
void
cmExportBuildFileGenerator
-::ComplainAboutMissingTarget(cmTarget* target, const char* dep)
+::ComplainAboutMissingTarget(cmTarget* depender,
+ cmTarget* dependee)
{
if(!this->ExportCommand || !this->ExportCommand->ErrorMessage.empty())
{
@@ -130,13 +131,10 @@ cmExportBuildFileGenerator
}
cmOStringStream e;
- e << "called with target \"" << target->GetName()
- << "\" which links to target \"" << dep
+ e << "called with target \"" << depender->GetName()
+ << "\" which requires target \"" << dependee->GetName()
<< "\" that is not in the export list.\n"
- << "If the link dependency is not part of the public interface "
- << "consider setting the LINK_INTERFACE_LIBRARIES property on \""
- << target->GetName() << "\". Otherwise add it to the export list. "
- << "If the link dependency is not easy to reference in this call, "
+ << "If the required target is not easy to reference in this call, "
<< "consider using the APPEND option with multiple separate calls.";
this->ExportCommand->ErrorMessage = e.str();
}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index 394e95a..ffda1e6 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -50,7 +50,8 @@ protected:
virtual void GenerateImportTargetsConfig(std::ostream& os,
const char* config,
std::string const& suffix);
- virtual void ComplainAboutMissingTarget(cmTarget* target, const char* dep);
+ virtual void ComplainAboutMissingTarget(cmTarget* depender,
+ cmTarget* dependee);
/** Fill in properties indicating built file locations. */
void SetImportLocationProperty(const char* config,
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 7b23b18..04946cf 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -245,7 +245,7 @@ cmExportFileGenerator
{
// We are not appending, so all exported targets should be
// known here. This is probably user-error.
- this->ComplainAboutMissingTarget(target, li->c_str());
+ this->ComplainAboutMissingTarget(target, tgt);
}
// Assume the target will be exported by another command.
// Append it with the export namespace.
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index 432bdb2..66aed56 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -85,7 +85,8 @@ protected:
/** Each subclass knows how to complain about a target that is
missing from an export set. */
- virtual void ComplainAboutMissingTarget(cmTarget*, const char* dep) = 0;
+ virtual void ComplainAboutMissingTarget(cmTarget* depender,
+ cmTarget* dependee) = 0;
// The namespace in which the exports are placed in the generated file.
std::string Namespace;
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 14bb816..e3ca3af 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -264,16 +264,12 @@ cmExportInstallFileGenerator
//----------------------------------------------------------------------------
void
cmExportInstallFileGenerator
-::ComplainAboutMissingTarget(cmTarget* target, const char* dep)
+::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee)
{
cmOStringStream e;
e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
- << "includes target \"" << target->GetName()
- << "\" which links to target \"" << dep
- << "\" that is not in the export set. "
- << "If the link dependency is not part of the public interface "
- << "consider setting the LINK_INTERFACE_LIBRARIES property on "
- << "target \"" << target->GetName() << "\". "
- << "Otherwise add it to the export set.";
+ << "includes target \"" << depender->GetName()
+ << "\" which requires target \"" << depender->GetName()
+ << "\" that is not in the export set.";
cmSystemTools::Error(e.str().c_str());
}
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
index ecae0b7..ffe05f7 100644
--- a/Source/cmExportInstallFileGenerator.h
+++ b/Source/cmExportInstallFileGenerator.h
@@ -66,7 +66,8 @@ protected:
virtual void GenerateImportTargetsConfig(std::ostream& os,
const char* config,
std::string const& suffix);
- virtual void ComplainAboutMissingTarget(cmTarget* target, const char* dep);
+ virtual void ComplainAboutMissingTarget(cmTarget* depender,
+ cmTarget* dependee);
/** Generate a per-configuration file for the targets. */
bool GenerateImportFileConfig(const char* config);
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 244c9e5..100b613 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1605,6 +1605,15 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
}
}
+ // Add the linker runtime search path if any.
+ std::string rpath_link = cli.GetRPathLinkString();
+ if(!cli.GetRPathLinkFlag().empty() && !rpath_link.empty())
+ {
+ fout << cli.GetRPathLinkFlag();
+ fout << this->EscapeForShell(rpath_link.c_str(), true);
+ fout << " ";
+ }
+
// Add standard libraries for this language.
std::string standardLibsVar = "CMAKE_";
standardLibsVar += cli.GetLinkLanguage();
diff --git a/Source/cmOrderRuntimeDirectories.cxx b/Source/cmOrderRuntimeDirectories.cxx
new file mode 100644
index 0000000..b0fe337
--- /dev/null
+++ b/Source/cmOrderRuntimeDirectories.cxx
@@ -0,0 +1,325 @@
+/*=========================================================================
+
+ 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
new file mode 100644
index 0000000..d249f8f
--- /dev/null
+++ b/Source/cmOrderRuntimeDirectories.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 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 ef2fde5..32c6638 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -193,13 +193,13 @@ void cmTarget::DefineProperties(cmake *cm)
"Shared libraries may be linked to other shared libraries as part "
"of their implementation. On some platforms the linker searches "
"for the dependent libraries of shared libraries they are including "
- "in the link. CMake gives the paths to these libraries to the linker "
- "by listing them on the link line explicitly. This property lists "
+ "in the link. This property lists "
"the dependent shared libraries of an imported library. The list "
"should be disjoint from the list of interface libraries in the "
"IMPORTED_LINK_INTERFACE_LIBRARIES property. On platforms requiring "
"dependent shared libraries to be found at link time CMake uses this "
- "list to add the dependent libraries to the link command line.");
+ "list to add appropriate files or paths to the link command line. "
+ "Ignored for non-imported targets.");
cm->DefineProperty
("IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>", cmProperty::TARGET,
diff --git a/bootstrap b/bootstrap
index e08dc01..6de4a02 100755
--- a/bootstrap
+++ b/bootstrap
@@ -169,6 +169,7 @@ CMAKE_CXX_SOURCES="\
cmListFileCache \
cmComputeLinkDepends \
cmComputeLinkInformation \
+ cmOrderRuntimeDirectories \
"
if ${cmake_system_mingw}; then