ENH: Pass dependent library search path to linker on some platforms.
- Move runtime path ordering out of cmComputeLinkInformation into its own class cmOrderRuntimeDirectories. - Create an instance of cmOrderRuntimeDirectories for runtime path ordering and another instance for dependent library path ordering. - Replace CMAKE_DEPENDENT_SHARED_LIBRARY_MODE with explicit CMAKE_LINK_DEPENDENT_LIBRARY_FILES boolean. - Create CMAKE_LINK_DEPENDENT_LIBRARY_DIRS boolean. - Create variables to specify -rpath-link flags: CMAKE_SHARED_LIBRARY_RPATH_LINK_<LANG>_FLAG CMAKE_EXECUTABLE_RPATH_LINK_<LANG>_FLAG - Enable -rpath-link flag on Linux and QNX. - Documentation and error message updates
This commit is contained in:
parent
f28f1585f6
commit
82fcaebe28
|
@ -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})
|
SET(CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
|
||||||
ENDIF(NOT CMAKE_EXECUTABLE_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(
|
MARK_AS_ADVANCED(
|
||||||
CMAKE_C_FLAGS
|
CMAKE_C_FLAGS
|
||||||
CMAKE_C_FLAGS_DEBUG
|
CMAKE_C_FLAGS_DEBUG
|
||||||
|
|
|
@ -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})
|
SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
|
||||||
ENDIF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_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)
|
IF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG)
|
||||||
SET(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG})
|
SET(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG})
|
||||||
ENDIF(NOT CMAKE_EXECUTABLE_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})
|
SET(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP})
|
||||||
ENDIF(NOT CMAKE_EXECUTABLE_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)
|
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})
|
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)
|
ENDIF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH)
|
||||||
|
|
|
@ -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})
|
SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
|
||||||
ENDIF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_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
|
# repeat for modules
|
||||||
IF(NOT CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS)
|
IF(NOT CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS)
|
||||||
SET(CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS ${CMAKE_SHARED_MODULE_CREATE_C_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})
|
SET(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP})
|
||||||
ENDIF(NOT CMAKE_EXECUTABLE_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)
|
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})
|
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)
|
ENDIF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH)
|
||||||
|
|
|
@ -107,7 +107,7 @@ ENDIF(XCODE)
|
||||||
# with -isysroot (for universal binaries), the linker always looks for
|
# with -isysroot (for universal binaries), the linker always looks for
|
||||||
# dependent libraries under the sysroot. Listing them on the link
|
# dependent libraries under the sysroot. Listing them on the link
|
||||||
# line works around the problem.
|
# 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>")
|
SET(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
|
||||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-rdynamic")
|
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-rdynamic")
|
||||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
|
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
|
||||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
|
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_C_FLAG "-Wl,-soname,")
|
||||||
SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
|
SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
|
||||||
SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-soname,")
|
SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-soname,")
|
||||||
|
|
|
@ -13,6 +13,7 @@ SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS "")
|
||||||
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
|
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared")
|
||||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
|
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
|
||||||
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
|
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_C_FLAG "-Wl,-soname,")
|
||||||
SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
|
SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
|
||||||
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
|
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
|
||||||
|
|
|
@ -161,6 +161,8 @@ SET(SRCS
|
||||||
cmMakefileExecutableTargetGenerator.cxx
|
cmMakefileExecutableTargetGenerator.cxx
|
||||||
cmMakefileLibraryTargetGenerator.cxx
|
cmMakefileLibraryTargetGenerator.cxx
|
||||||
cmMakefileUtilityTargetGenerator.cxx
|
cmMakefileUtilityTargetGenerator.cxx
|
||||||
|
cmOrderRuntimeDirectories.cxx
|
||||||
|
cmOrderRuntimeDirectories.h
|
||||||
cmProperty.cxx
|
cmProperty.cxx
|
||||||
cmProperty.h
|
cmProperty.h
|
||||||
cmPropertyDefinition.cxx
|
cmPropertyDefinition.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
|
edges are sorted by this index. This preserves the original link
|
||||||
order as much as possible subject to the dependencies.
|
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.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -17,14 +17,13 @@
|
||||||
#include "cmComputeLinkInformation.h"
|
#include "cmComputeLinkInformation.h"
|
||||||
|
|
||||||
#include "cmComputeLinkDepends.h"
|
#include "cmComputeLinkDepends.h"
|
||||||
|
#include "cmOrderRuntimeDirectories.h"
|
||||||
|
|
||||||
#include "cmGlobalGenerator.h"
|
#include "cmGlobalGenerator.h"
|
||||||
#include "cmLocalGenerator.h"
|
#include "cmLocalGenerator.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmTarget.h"
|
#include "cmTarget.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#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
|
or SHLIB_PATH, in searching for shared libraries. This changes
|
||||||
the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
|
the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
|
||||||
RPATH (embedded path).
|
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.
|
// The configuration being linked.
|
||||||
this->Config = config;
|
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.
|
// Get the language used for linking this target.
|
||||||
this->LinkLanguage =
|
this->LinkLanguage =
|
||||||
this->Target->GetLinkerLanguage(this->GlobalGenerator);
|
this->Target->GetLinkerLanguage(this->GlobalGenerator);
|
||||||
|
@ -204,15 +271,11 @@ cmComputeLinkInformation
|
||||||
this->RuntimeUseChrpath = false;
|
this->RuntimeUseChrpath = false;
|
||||||
if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
|
if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
|
||||||
{
|
{
|
||||||
|
const char* tType =
|
||||||
|
((this->Target->GetType() == cmTarget::EXECUTABLE)?
|
||||||
|
"EXECUTABLE" : "SHARED_LIBRARY");
|
||||||
std::string rtVar = "CMAKE_";
|
std::string rtVar = "CMAKE_";
|
||||||
if(this->Target->GetType() == cmTarget::EXECUTABLE)
|
rtVar += tType;
|
||||||
{
|
|
||||||
rtVar += "EXECUTABLE";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rtVar += "SHARED_LIBRARY";
|
|
||||||
}
|
|
||||||
rtVar += "_RUNTIME_";
|
rtVar += "_RUNTIME_";
|
||||||
rtVar += this->LinkLanguage;
|
rtVar += this->LinkLanguage;
|
||||||
rtVar += "_FLAG";
|
rtVar += "_FLAG";
|
||||||
|
@ -223,6 +286,14 @@ cmComputeLinkInformation
|
||||||
(this->Makefile->
|
(this->Makefile->
|
||||||
GetSafeDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
|
GetSafeDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
|
||||||
this->RuntimeUseChrpath = this->Target->IsChrpathUsed();
|
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.
|
// Get link type information.
|
||||||
|
@ -236,17 +307,23 @@ cmComputeLinkInformation
|
||||||
|
|
||||||
// Choose a mode for dealing with shared library dependencies.
|
// Choose a mode for dealing with shared library dependencies.
|
||||||
this->SharedDependencyMode = SharedDepModeNone;
|
this->SharedDependencyMode = SharedDepModeNone;
|
||||||
if(const char* mode =
|
if(this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES"))
|
||||||
this->Makefile->GetDefinition("CMAKE_DEPENDENT_SHARED_LIBRARY_MODE"))
|
|
||||||
{
|
{
|
||||||
if(strcmp(mode, "LINK") == 0)
|
this->SharedDependencyMode = SharedDepModeLink;
|
||||||
{
|
}
|
||||||
this->SharedDependencyMode = SharedDepModeLink;
|
else if(this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS"))
|
||||||
}
|
{
|
||||||
else if(strcmp(mode, "DIR") == 0)
|
this->SharedDependencyMode = SharedDepModeDir;
|
||||||
{
|
}
|
||||||
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.
|
// Get the implicit link directories for this platform.
|
||||||
|
@ -265,7 +342,6 @@ cmComputeLinkInformation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial state.
|
// Initial state.
|
||||||
this->RuntimeSearchPathComputed = false;
|
|
||||||
this->HaveUserFlagItem = false;
|
this->HaveUserFlagItem = false;
|
||||||
|
|
||||||
// Decide whether to enable compatible library search path mode.
|
// Decide whether to enable compatible library search path mode.
|
||||||
|
@ -288,6 +364,13 @@ cmComputeLinkInformation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmComputeLinkInformation::~cmComputeLinkInformation()
|
||||||
|
{
|
||||||
|
delete this->OrderRuntimeSearchPath;
|
||||||
|
delete this->OrderDependentRPath;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
cmComputeLinkInformation::ItemVector const&
|
cmComputeLinkInformation::ItemVector const&
|
||||||
cmComputeLinkInformation::GetItems()
|
cmComputeLinkInformation::GetItems()
|
||||||
|
@ -301,6 +384,31 @@ std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
|
||||||
return this->Directories;
|
return this->Directories;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
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()
|
std::vector<std::string> const& cmComputeLinkInformation::GetDepends()
|
||||||
{
|
{
|
||||||
|
@ -350,7 +458,14 @@ bool cmComputeLinkInformation::Compute()
|
||||||
lei = linkEntries.begin();
|
lei = linkEntries.begin();
|
||||||
lei != linkEntries.end(); ++lei)
|
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
|
// Restore the target link type so the correct system runtime
|
||||||
|
@ -372,15 +487,8 @@ bool cmComputeLinkInformation::Compute()
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeLinkInformation::AddItem(std::string const& item,
|
void cmComputeLinkInformation::AddItem(std::string const& item, cmTarget* tgt)
|
||||||
cmTarget* tgt, bool isSharedDep)
|
|
||||||
{
|
{
|
||||||
// If dropping shared library dependencies, ignore them.
|
|
||||||
if(isSharedDep && this->SharedDependencyMode == SharedDepModeNone)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the proper name to use to link this library.
|
// Compute the proper name to use to link this library.
|
||||||
const char* config = this->Config;
|
const char* config = this->Config;
|
||||||
bool impexe = (tgt && tgt->IsExecutableWithExports());
|
bool impexe = (tgt && tgt->IsExecutableWithExports());
|
||||||
|
@ -416,14 +524,6 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
|
||||||
(this->UseImportLibrary &&
|
(this->UseImportLibrary &&
|
||||||
(impexe || tgt->GetType() == cmTarget::SHARED_LIBRARY));
|
(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.
|
// Pass the full path to the target file.
|
||||||
std::string lib = tgt->GetFullPath(config, implib);
|
std::string lib = tgt->GetFullPath(config, implib);
|
||||||
this->Depends.push_back(lib);
|
this->Depends.push_back(lib);
|
||||||
|
@ -434,7 +534,6 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
|
||||||
// link.
|
// link.
|
||||||
std::string fw = tgt->GetDirectory(config, implib);
|
std::string fw = tgt->GetDirectory(config, implib);
|
||||||
this->AddFrameworkItem(fw);
|
this->AddFrameworkItem(fw);
|
||||||
this->SharedLibrariesLinked.insert(tgt);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -469,6 +568,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()
|
void cmComputeLinkInformation::ComputeLinkTypeInfo()
|
||||||
{
|
{
|
||||||
|
@ -1022,17 +1199,14 @@ void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
|
||||||
this->AddLinkerSearchDirectories(this->OldLinkDirs);
|
this->AddLinkerSearchDirectories(this->OldLinkDirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help the linker find dependent shared libraries.
|
// If there is no separate linker runtime search flag (-rpath-link)
|
||||||
if(this->SharedDependencyMode == SharedDepModeDir)
|
// 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
|
this->AddLinkerSearchDirectories
|
||||||
// path ordering analysis. However they are a bit different.
|
(this->OrderDependentRPath->GetRuntimePath());
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -1054,23 +1228,9 @@ cmComputeLinkInformation
|
||||||
std::vector<std::string> const&
|
std::vector<std::string> const&
|
||||||
cmComputeLinkInformation::GetRuntimeSearchPath()
|
cmComputeLinkInformation::GetRuntimeSearchPath()
|
||||||
{
|
{
|
||||||
if(!this->RuntimeSearchPathComputed)
|
return this->OrderRuntimeSearchPath->GetRuntimePath();
|
||||||
{
|
|
||||||
this->RuntimeSearchPathComputed = true;
|
|
||||||
this->CollectRuntimeDirectories();
|
|
||||||
this->FindConflictingLibraries();
|
|
||||||
this->OrderRuntimeSearchPath();
|
|
||||||
}
|
|
||||||
return this->RuntimeSearchPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
// 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
|
void
|
||||||
cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
|
cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
|
||||||
|
@ -1104,262 +1264,8 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the runtime information at most once.
|
// Include this library in the runtime path ordering.
|
||||||
if(this->LibraryRuntimeInfoEmmitted.insert(fullPath).second)
|
this->OrderRuntimeSearchPath->AddLibrary(fullPath, soname);
|
||||||
{
|
|
||||||
// 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -25,6 +25,7 @@ class cmGlobalGenerator;
|
||||||
class cmLocalGenerator;
|
class cmLocalGenerator;
|
||||||
class cmMakefile;
|
class cmMakefile;
|
||||||
class cmTarget;
|
class cmTarget;
|
||||||
|
class cmOrderRuntimeDirectories;
|
||||||
|
|
||||||
/** \class cmComputeLinkInformation
|
/** \class cmComputeLinkInformation
|
||||||
* \brief Compute link information for a target in one configuration.
|
* \brief Compute link information for a target in one configuration.
|
||||||
|
@ -33,6 +34,7 @@ class cmComputeLinkInformation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cmComputeLinkInformation(cmTarget* target, const char* config);
|
cmComputeLinkInformation(cmTarget* target, const char* config);
|
||||||
|
~cmComputeLinkInformation();
|
||||||
bool Compute();
|
bool Compute();
|
||||||
|
|
||||||
struct Item
|
struct Item
|
||||||
|
@ -57,8 +59,12 @@ public:
|
||||||
std::string GetChrpathString();
|
std::string GetChrpathString();
|
||||||
std::string GetChrpathTool();
|
std::string GetChrpathTool();
|
||||||
std::set<cmTarget*> const& GetSharedLibrariesLinked();
|
std::set<cmTarget*> const& GetSharedLibrariesLinked();
|
||||||
|
|
||||||
|
std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }
|
||||||
|
std::string GetRPathLinkString();
|
||||||
private:
|
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.
|
// Output information.
|
||||||
ItemVector Items;
|
ItemVector Items;
|
||||||
|
@ -96,6 +102,7 @@ private:
|
||||||
std::string RuntimeSep;
|
std::string RuntimeSep;
|
||||||
std::string RuntimeAlways;
|
std::string RuntimeAlways;
|
||||||
bool RuntimeUseChrpath;
|
bool RuntimeUseChrpath;
|
||||||
|
std::string RPathLinkFlag;
|
||||||
SharedDepMode SharedDependencyMode;
|
SharedDepMode SharedDependencyMode;
|
||||||
|
|
||||||
// Link type adjustment.
|
// Link type adjustment.
|
||||||
|
@ -143,7 +150,6 @@ private:
|
||||||
void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
|
void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
|
||||||
std::set<cmStdString> DirectoriesEmmitted;
|
std::set<cmStdString> DirectoriesEmmitted;
|
||||||
std::set<cmStdString> ImplicitLinkDirs;
|
std::set<cmStdString> ImplicitLinkDirs;
|
||||||
std::vector<std::string> SharedDependencyDirectories;
|
|
||||||
|
|
||||||
// Linker search path compatibility mode.
|
// Linker search path compatibility mode.
|
||||||
std::vector<std::string> OldLinkDirs;
|
std::vector<std::string> OldLinkDirs;
|
||||||
|
@ -151,48 +157,13 @@ private:
|
||||||
bool HaveUserFlagItem;
|
bool HaveUserFlagItem;
|
||||||
|
|
||||||
// Runtime path computation.
|
// Runtime path computation.
|
||||||
struct LibraryRuntimeEntry
|
cmOrderRuntimeDirectories* OrderRuntimeSearchPath;
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
void AddLibraryRuntimeInfo(std::string const& fullPath, cmTarget* target);
|
void AddLibraryRuntimeInfo(std::string const& fullPath, cmTarget* target);
|
||||||
void AddLibraryRuntimeInfo(std::string const& fullPath,
|
void AddLibraryRuntimeInfo(std::string const& fullPath,
|
||||||
const char* soname = 0);
|
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.
|
// Dependent library path computation.
|
||||||
// This maps from directory to those that must come *before* it.
|
cmOrderRuntimeDirectories* OrderDependentRPath;
|
||||||
// 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
|
#endif
|
||||||
|
|
|
@ -1086,10 +1086,14 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
|
||||||
cmProperty::VARIABLE,0,0);
|
cmProperty::VARIABLE,0,0);
|
||||||
cm->DefineProperty("CMAKE_SHARED_LIBRARY_RUNTIME_<LANG>_FLAG_SEP",
|
cm->DefineProperty("CMAKE_SHARED_LIBRARY_RUNTIME_<LANG>_FLAG_SEP",
|
||||||
cmProperty::VARIABLE,0,0);
|
cmProperty::VARIABLE,0,0);
|
||||||
|
cm->DefineProperty("CMAKE_SHARED_LIBRARY_RPATH_LINK_<LANG>_FLAG",
|
||||||
|
cmProperty::VARIABLE,0,0);
|
||||||
cm->DefineProperty("CMAKE_EXECUTABLE_RUNTIME_<LANG>_FLAG",
|
cm->DefineProperty("CMAKE_EXECUTABLE_RUNTIME_<LANG>_FLAG",
|
||||||
cmProperty::VARIABLE,0,0);
|
cmProperty::VARIABLE,0,0);
|
||||||
cm->DefineProperty("CMAKE_EXECUTABLE_RUNTIME_<LANG>_FLAG_SEP",
|
cm->DefineProperty("CMAKE_EXECUTABLE_RUNTIME_<LANG>_FLAG_SEP",
|
||||||
cmProperty::VARIABLE,0,0);
|
cmProperty::VARIABLE,0,0);
|
||||||
|
cm->DefineProperty("CMAKE_EXECUTABLE_RPATH_LINK_<LANG>_FLAG",
|
||||||
|
cmProperty::VARIABLE,0,0);
|
||||||
cm->DefineProperty("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH",
|
cm->DefineProperty("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH",
|
||||||
cmProperty::VARIABLE,0,0);
|
cmProperty::VARIABLE,0,0);
|
||||||
cm->DefineProperty("CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS",
|
cm->DefineProperty("CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS",
|
||||||
|
@ -1104,7 +1108,8 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
|
||||||
cmProperty::VARIABLE,0,0);
|
cmProperty::VARIABLE,0,0);
|
||||||
cm->DefineProperty("CMAKE_SHARED_MODULE_RUNTIME_<LANG>_FLAG_SEP",
|
cm->DefineProperty("CMAKE_SHARED_MODULE_RUNTIME_<LANG>_FLAG_SEP",
|
||||||
cmProperty::VARIABLE,0,0);
|
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);
|
cmProperty::VARIABLE,0,0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,8 @@ cmExportBuildFileGenerator
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void
|
void
|
||||||
cmExportBuildFileGenerator
|
cmExportBuildFileGenerator
|
||||||
::ComplainAboutMissingTarget(cmTarget* target, const char* dep)
|
::ComplainAboutMissingTarget(cmTarget* depender,
|
||||||
|
cmTarget* dependee)
|
||||||
{
|
{
|
||||||
if(!this->ExportCommand || !this->ExportCommand->ErrorMessage.empty())
|
if(!this->ExportCommand || !this->ExportCommand->ErrorMessage.empty())
|
||||||
{
|
{
|
||||||
|
@ -130,13 +131,10 @@ cmExportBuildFileGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
e << "called with target \"" << target->GetName()
|
e << "called with target \"" << depender->GetName()
|
||||||
<< "\" which links to target \"" << dep
|
<< "\" which requires target \"" << dependee->GetName()
|
||||||
<< "\" that is not in the export list.\n"
|
<< "\" that is not in the export list.\n"
|
||||||
<< "If the link dependency is not part of the public interface "
|
<< "If the required target is not easy to reference in this call, "
|
||||||
<< "consider setting the LINK_INTERFACE_LIBRARIES property on \""
|
|
||||||
<< target->GetName() << "\". Otherwise add it to the export list. "
|
|
||||||
<< "If the link dependency is not easy to reference in this call, "
|
|
||||||
<< "consider using the APPEND option with multiple separate calls.";
|
<< "consider using the APPEND option with multiple separate calls.";
|
||||||
this->ExportCommand->ErrorMessage = e.str();
|
this->ExportCommand->ErrorMessage = e.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@ protected:
|
||||||
virtual void GenerateImportTargetsConfig(std::ostream& os,
|
virtual void GenerateImportTargetsConfig(std::ostream& os,
|
||||||
const char* config,
|
const char* config,
|
||||||
std::string const& suffix);
|
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. */
|
/** Fill in properties indicating built file locations. */
|
||||||
void SetImportLocationProperty(const char* config,
|
void SetImportLocationProperty(const char* config,
|
||||||
|
|
|
@ -245,7 +245,7 @@ cmExportFileGenerator
|
||||||
{
|
{
|
||||||
// We are not appending, so all exported targets should be
|
// We are not appending, so all exported targets should be
|
||||||
// known here. This is probably user-error.
|
// 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.
|
// Assume the target will be exported by another command.
|
||||||
// Append it with the export namespace.
|
// Append it with the export namespace.
|
||||||
|
|
|
@ -85,7 +85,8 @@ protected:
|
||||||
|
|
||||||
/** Each subclass knows how to complain about a target that is
|
/** Each subclass knows how to complain about a target that is
|
||||||
missing from an export set. */
|
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.
|
// The namespace in which the exports are placed in the generated file.
|
||||||
std::string Namespace;
|
std::string Namespace;
|
||||||
|
|
|
@ -264,16 +264,12 @@ cmExportInstallFileGenerator
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void
|
void
|
||||||
cmExportInstallFileGenerator
|
cmExportInstallFileGenerator
|
||||||
::ComplainAboutMissingTarget(cmTarget* target, const char* dep)
|
::ComplainAboutMissingTarget(cmTarget* depender, cmTarget* dependee)
|
||||||
{
|
{
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
|
e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
|
||||||
<< "includes target \"" << target->GetName()
|
<< "includes target \"" << depender->GetName()
|
||||||
<< "\" which links to target \"" << dep
|
<< "\" which requires target \"" << depender->GetName()
|
||||||
<< "\" that is not in the export set. "
|
<< "\" that is not in the export set.";
|
||||||
<< "If the link dependency is not part of the public interface "
|
|
||||||
<< "consider setting the LINK_INTERFACE_LIBRARIES property on "
|
|
||||||
<< "target \"" << target->GetName() << "\". "
|
|
||||||
<< "Otherwise add it to the export set.";
|
|
||||||
cmSystemTools::Error(e.str().c_str());
|
cmSystemTools::Error(e.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,8 @@ protected:
|
||||||
virtual void GenerateImportTargetsConfig(std::ostream& os,
|
virtual void GenerateImportTargetsConfig(std::ostream& os,
|
||||||
const char* config,
|
const char* config,
|
||||||
std::string const& suffix);
|
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. */
|
/** Generate a per-configuration file for the targets. */
|
||||||
bool GenerateImportFileConfig(const char* config);
|
bool GenerateImportFileConfig(const char* config);
|
||||||
|
|
|
@ -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.
|
// Add standard libraries for this language.
|
||||||
std::string standardLibsVar = "CMAKE_";
|
std::string standardLibsVar = "CMAKE_";
|
||||||
standardLibsVar += cli.GetLinkLanguage();
|
standardLibsVar += cli.GetLinkLanguage();
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
|
@ -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
|
|
@ -193,13 +193,13 @@ void cmTarget::DefineProperties(cmake *cm)
|
||||||
"Shared libraries may be linked to other shared libraries as part "
|
"Shared libraries may be linked to other shared libraries as part "
|
||||||
"of their implementation. On some platforms the linker searches "
|
"of their implementation. On some platforms the linker searches "
|
||||||
"for the dependent libraries of shared libraries they are including "
|
"for the dependent libraries of shared libraries they are including "
|
||||||
"in the link. CMake gives the paths to these libraries to the linker "
|
"in the link. This property lists "
|
||||||
"by listing them on the link line explicitly. This property lists "
|
|
||||||
"the dependent shared libraries of an imported library. The list "
|
"the dependent shared libraries of an imported library. The list "
|
||||||
"should be disjoint from the list of interface libraries in the "
|
"should be disjoint from the list of interface libraries in the "
|
||||||
"IMPORTED_LINK_INTERFACE_LIBRARIES property. On platforms requiring "
|
"IMPORTED_LINK_INTERFACE_LIBRARIES property. On platforms requiring "
|
||||||
"dependent shared libraries to be found at link time CMake uses this "
|
"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
|
cm->DefineProperty
|
||||||
("IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>", cmProperty::TARGET,
|
("IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>", cmProperty::TARGET,
|
||||||
|
|
Loading…
Reference in New Issue