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})
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>")
|
||||
|
||||
|
|
|
@ -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,")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -161,6 +161,8 @@ SET(SRCS
|
|||
cmMakefileExecutableTargetGenerator.cxx
|
||||
cmMakefileLibraryTargetGenerator.cxx
|
||||
cmMakefileUtilityTargetGenerator.cxx
|
||||
cmOrderRuntimeDirectories.cxx
|
||||
cmOrderRuntimeDirectories.h
|
||||
cmProperty.cxx
|
||||
cmProperty.h
|
||||
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
|
||||
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 "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.
|
||||
|
@ -288,6 +364,13 @@ cmComputeLinkInformation
|
|||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
cmComputeLinkInformation::~cmComputeLinkInformation()
|
||||
{
|
||||
delete this->OrderRuntimeSearchPath;
|
||||
delete this->OrderDependentRPath;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
cmComputeLinkInformation::ItemVector const&
|
||||
cmComputeLinkInformation::GetItems()
|
||||
|
@ -301,6 +384,31 @@ std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
|
|||
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()
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 "
|
||||
"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,
|
||||
|
|
Loading…
Reference in New Issue