ENH: Better linker search path computation.
- Use linker search path -L.. -lfoo for lib w/out soname when platform sets CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME - Rename cmOrderRuntimeDirectories to cmOrderDirectories and generalize it for both soname constraints and link library constraints - Use cmOrderDirectories to order -L directories based on all needed constraints - Avoid processing implicit link directories - For CMAKE_OLD_LINK_PATHS add constraints from libs producing them to produce old ordering
This commit is contained in:
parent
9f2f456e7d
commit
fd37a6ec3d
|
@ -12,6 +12,10 @@ IF(EXISTS /usr/include/dlfcn.h)
|
||||||
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
|
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
|
||||||
ENDIF(EXISTS /usr/include/dlfcn.h)
|
ENDIF(EXISTS /usr/include/dlfcn.h)
|
||||||
|
|
||||||
|
# Shared libraries with no builtin soname may not be linked safely by
|
||||||
|
# specifying the file path.
|
||||||
|
SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
|
||||||
|
|
||||||
# Initialize C link type selection flags. These flags are used when
|
# Initialize C link type selection flags. These flags are used when
|
||||||
# building a shared library, shared module, or executable that links
|
# building a shared library, shared module, or executable that links
|
||||||
# to other libraries to select whether to use the static or shared
|
# to other libraries to select whether to use the static or shared
|
||||||
|
|
|
@ -8,6 +8,10 @@ SET(CMAKE_FIND_LIBRARY_SUFFIXES ".sl" ".so" ".a")
|
||||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH 1)
|
SET(CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH 1)
|
||||||
SET(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
|
SET(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
|
||||||
|
|
||||||
|
# Shared libraries with no builtin soname may not be linked safely by
|
||||||
|
# specifying the file path.
|
||||||
|
SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
|
||||||
|
|
||||||
# fortran
|
# fortran
|
||||||
IF(CMAKE_COMPILER_IS_GNUG77)
|
IF(CMAKE_COMPILER_IS_GNUG77)
|
||||||
SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-fPIC") # -pic
|
SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-fPIC") # -pic
|
||||||
|
|
|
@ -12,6 +12,10 @@ SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,-soname,")
|
||||||
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
|
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
|
||||||
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
|
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
|
||||||
|
|
||||||
|
# Shared libraries with no builtin soname may not be linked safely by
|
||||||
|
# specifying the file path.
|
||||||
|
SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
|
||||||
|
|
||||||
# Initialize C link type selection flags. These flags are used when
|
# Initialize C link type selection flags. These flags are used when
|
||||||
# building a shared library, shared module, or executable that links
|
# building a shared library, shared module, or executable that links
|
||||||
# to other libraries to select whether to use the static or shared
|
# to other libraries to select whether to use the static or shared
|
||||||
|
|
|
@ -19,6 +19,10 @@ SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,-soname,")
|
||||||
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
|
SET(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
|
||||||
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
|
SET(CMAKE_EXE_EXPORTS_CXX_FLAG "-Wl,--export-dynamic")
|
||||||
|
|
||||||
|
# Shared libraries with no builtin soname may not be linked safely by
|
||||||
|
# specifying the file path.
|
||||||
|
SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
|
||||||
|
|
||||||
# Initialize C link type selection flags. These flags are used when
|
# Initialize C link type selection flags. These flags are used when
|
||||||
# building a shared library, shared module, or executable that links
|
# building a shared library, shared module, or executable that links
|
||||||
# to other libraries to select whether to use the static or shared
|
# to other libraries to select whether to use the static or shared
|
||||||
|
|
|
@ -103,4 +103,6 @@ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
# in the -L path.
|
# in the -L path.
|
||||||
SET(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
|
SET(CMAKE_LINK_DEPENDENT_LIBRARY_DIRS 1)
|
||||||
|
|
||||||
|
# Shared libraries with no builtin soname may not be linked safely by
|
||||||
|
# specifying the file path.
|
||||||
|
SET(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
|
||||||
|
|
|
@ -167,8 +167,8 @@ SET(SRCS
|
||||||
cmMakefileExecutableTargetGenerator.cxx
|
cmMakefileExecutableTargetGenerator.cxx
|
||||||
cmMakefileLibraryTargetGenerator.cxx
|
cmMakefileLibraryTargetGenerator.cxx
|
||||||
cmMakefileUtilityTargetGenerator.cxx
|
cmMakefileUtilityTargetGenerator.cxx
|
||||||
cmOrderRuntimeDirectories.cxx
|
cmOrderDirectories.cxx
|
||||||
cmOrderRuntimeDirectories.h
|
cmOrderDirectories.h
|
||||||
cmProperty.cxx
|
cmProperty.cxx
|
||||||
cmProperty.h
|
cmProperty.h
|
||||||
cmPropertyDefinition.cxx
|
cmPropertyDefinition.cxx
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "cmComputeLinkInformation.h"
|
#include "cmComputeLinkInformation.h"
|
||||||
|
|
||||||
#include "cmComputeLinkDepends.h"
|
#include "cmComputeLinkDepends.h"
|
||||||
#include "cmOrderRuntimeDirectories.h"
|
#include "cmOrderDirectories.h"
|
||||||
|
|
||||||
#include "cmGlobalGenerator.h"
|
#include "cmGlobalGenerator.h"
|
||||||
#include "cmLocalGenerator.h"
|
#include "cmLocalGenerator.h"
|
||||||
|
@ -212,6 +212,30 @@ libraries that are also linked need to be listed in -L paths.
|
||||||
In our implementation we add all dependent libraries to the runtime
|
In our implementation we add all dependent libraries to the runtime
|
||||||
path computation. Then the auto-generated RPATH will find everything.
|
path computation. Then the auto-generated RPATH will find everything.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Notes about shared libraries with not builtin soname:
|
||||||
|
|
||||||
|
Some UNIX shared libraries may be created with no builtin soname. On
|
||||||
|
some platforms such libraries cannot be linked using the path to their
|
||||||
|
location because the linker will copy the path into the field used to
|
||||||
|
find the library at runtime.
|
||||||
|
|
||||||
|
Apple: ../libfoo.dylib ==> libfoo.dylib # ok, uses install_name
|
||||||
|
SGI: ../libfoo.so ==> libfoo.so # ok
|
||||||
|
AIX: ../libfoo.so ==> libfoo.so # ok
|
||||||
|
Linux: ../libfoo.so ==> ../libfoo.so # bad
|
||||||
|
HP-UX: ../libfoo.so ==> ../libfoo.so # bad
|
||||||
|
Sun: ../libfoo.so ==> ../libfoo.so # bad
|
||||||
|
FreeBSD: ../libfoo.so ==> ../libfoo.so # bad
|
||||||
|
|
||||||
|
In order to link these libraries we need to use the old-style split
|
||||||
|
into -L.. and -lfoo options. This should be fairly safe because most
|
||||||
|
problems with -lfoo options were related to selecting shared libraries
|
||||||
|
instead of static but in this case we want the shared lib. Link
|
||||||
|
directory ordering needs to be done to make sure these shared
|
||||||
|
libraries are found first. There should be very few restrictions
|
||||||
|
because this need be done only for shared libraries without soname-s.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -229,9 +253,12 @@ cmComputeLinkInformation
|
||||||
this->Config = config;
|
this->Config = config;
|
||||||
|
|
||||||
// Allocate internals.
|
// Allocate internals.
|
||||||
|
this->OrderLinkerSearchPath =
|
||||||
|
new cmOrderDirectories(this->GlobalGenerator, target->GetName(),
|
||||||
|
"linker search path");
|
||||||
this->OrderRuntimeSearchPath =
|
this->OrderRuntimeSearchPath =
|
||||||
new cmOrderRuntimeDirectories(this->GlobalGenerator, target->GetName(),
|
new cmOrderDirectories(this->GlobalGenerator, target->GetName(),
|
||||||
"runtime path");
|
"runtime search path");
|
||||||
this->OrderDependentRPath = 0;
|
this->OrderDependentRPath = 0;
|
||||||
|
|
||||||
// Get the language used for linking this target.
|
// Get the language used for linking this target.
|
||||||
|
@ -298,6 +325,18 @@ cmComputeLinkInformation
|
||||||
this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar.c_str());
|
this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we need to include the runtime search path at link time.
|
||||||
|
{
|
||||||
|
std::string var = "CMAKE_SHARED_LIBRARY_LINK_";
|
||||||
|
var += this->LinkLanguage;
|
||||||
|
var += "_WITH_RUNTIME_PATH";
|
||||||
|
this->LinkWithRuntimePath = this->Makefile->IsOn(var.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the platform policy for missing soname case.
|
||||||
|
this->NoSONameUsesPath =
|
||||||
|
this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");
|
||||||
|
|
||||||
// Get link type information.
|
// Get link type information.
|
||||||
this->ComputeLinkTypeInfo();
|
this->ComputeLinkTypeInfo();
|
||||||
|
|
||||||
|
@ -315,24 +354,16 @@ cmComputeLinkInformation
|
||||||
}
|
}
|
||||||
else if(this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS"))
|
else if(this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS"))
|
||||||
{
|
{
|
||||||
this->SharedDependencyMode = SharedDepModeDir;
|
this->SharedDependencyMode = SharedDepModeLibDir;
|
||||||
}
|
}
|
||||||
else if(!this->RPathLinkFlag.empty())
|
else if(!this->RPathLinkFlag.empty())
|
||||||
{
|
{
|
||||||
this->SharedDependencyMode = SharedDepModeDir;
|
this->SharedDependencyMode = SharedDepModeDir;
|
||||||
}
|
|
||||||
if(this->SharedDependencyMode == SharedDepModeDir)
|
|
||||||
{
|
|
||||||
this->OrderDependentRPath =
|
this->OrderDependentRPath =
|
||||||
new cmOrderRuntimeDirectories(this->GlobalGenerator, target->GetName(),
|
new cmOrderDirectories(this->GlobalGenerator, target->GetName(),
|
||||||
"dependent library path");
|
"dependent library path");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the search path entries requested by the user to the runtime
|
|
||||||
// path computation.
|
|
||||||
this->OrderRuntimeSearchPath->AddDirectories(
|
|
||||||
this->Target->GetLinkDirectories());
|
|
||||||
|
|
||||||
// Get the implicit link directories for this platform.
|
// Get the implicit link directories for this platform.
|
||||||
if(const char* implicitLinks =
|
if(const char* implicitLinks =
|
||||||
(this->Makefile->GetDefinition
|
(this->Makefile->GetDefinition
|
||||||
|
@ -348,6 +379,21 @@ cmComputeLinkInformation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the search path entries requested by the user to path ordering.
|
||||||
|
this->OrderLinkerSearchPath
|
||||||
|
->AddUserDirectories(this->Target->GetLinkDirectories());
|
||||||
|
this->OrderRuntimeSearchPath
|
||||||
|
->AddUserDirectories(this->Target->GetLinkDirectories());
|
||||||
|
this->OrderLinkerSearchPath
|
||||||
|
->SetImplicitDirectories(this->ImplicitLinkDirs);
|
||||||
|
this->OrderRuntimeSearchPath
|
||||||
|
->SetImplicitDirectories(this->ImplicitLinkDirs);
|
||||||
|
if(this->OrderDependentRPath)
|
||||||
|
{
|
||||||
|
this->OrderDependentRPath
|
||||||
|
->SetImplicitDirectories(this->ImplicitLinkDirs);
|
||||||
|
}
|
||||||
|
|
||||||
// Initial state.
|
// Initial state.
|
||||||
this->HaveUserFlagItem = false;
|
this->HaveUserFlagItem = false;
|
||||||
|
|
||||||
|
@ -374,6 +420,7 @@ cmComputeLinkInformation
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
cmComputeLinkInformation::~cmComputeLinkInformation()
|
cmComputeLinkInformation::~cmComputeLinkInformation()
|
||||||
{
|
{
|
||||||
|
delete this->OrderLinkerSearchPath;
|
||||||
delete this->OrderRuntimeSearchPath;
|
delete this->OrderRuntimeSearchPath;
|
||||||
delete this->OrderDependentRPath;
|
delete this->OrderDependentRPath;
|
||||||
}
|
}
|
||||||
|
@ -388,7 +435,7 @@ cmComputeLinkInformation::GetItems()
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
|
std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
|
||||||
{
|
{
|
||||||
return this->Directories;
|
return this->OrderLinkerSearchPath->GetOrderedDirectories();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -396,7 +443,7 @@ std::string cmComputeLinkInformation::GetRPathLinkString()
|
||||||
{
|
{
|
||||||
// If there is no separate linker runtime search flag (-rpath-link)
|
// If there is no separate linker runtime search flag (-rpath-link)
|
||||||
// there is no reason to compute a string.
|
// there is no reason to compute a string.
|
||||||
if(!this->OrderDependentRPath || this->RPathLinkFlag.empty())
|
if(!this->OrderDependentRPath)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -405,7 +452,7 @@ std::string cmComputeLinkInformation::GetRPathLinkString()
|
||||||
std::string rpath_link;
|
std::string rpath_link;
|
||||||
const char* sep = "";
|
const char* sep = "";
|
||||||
std::vector<std::string> const& dirs =
|
std::vector<std::string> const& dirs =
|
||||||
this->OrderDependentRPath->GetRuntimePath();
|
this->OrderDependentRPath->GetOrderedDirectories();
|
||||||
for(std::vector<std::string>::const_iterator di = dirs.begin();
|
for(std::vector<std::string>::const_iterator di = dirs.begin();
|
||||||
di != dirs.end(); ++di)
|
di != dirs.end(); ++di)
|
||||||
{
|
{
|
||||||
|
@ -487,8 +534,8 @@ bool cmComputeLinkInformation::Compute()
|
||||||
this->SetCurrentLinkType(this->StartLinkType);
|
this->SetCurrentLinkType(this->StartLinkType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the linker search path.
|
// Finish setting up linker search directories.
|
||||||
this->ComputeLinkerSearchDirectories();
|
this->FinishLinkerSearchDirectories();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -637,19 +684,31 @@ void cmComputeLinkInformation::AddSharedDepItem(std::string const& item,
|
||||||
this->AddLibraryRuntimeInfo(lib);
|
this->AddLibraryRuntimeInfo(lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the item to the separate dependent library search path if
|
// Check if we need to include the dependent shared library in other
|
||||||
// this platform wants one.
|
// path ordering.
|
||||||
if(this->OrderDependentRPath)
|
cmOrderDirectories* order = 0;
|
||||||
|
if(this->SharedDependencyMode == SharedDepModeLibDir &&
|
||||||
|
!this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */)
|
||||||
|
{
|
||||||
|
// Add the item to the linker search path.
|
||||||
|
order = this->OrderLinkerSearchPath;
|
||||||
|
}
|
||||||
|
else if(this->SharedDependencyMode == SharedDepModeDir)
|
||||||
|
{
|
||||||
|
// Add the item to the separate dependent library search path.
|
||||||
|
order = this->OrderDependentRPath;
|
||||||
|
}
|
||||||
|
if(order)
|
||||||
{
|
{
|
||||||
if(tgt)
|
if(tgt)
|
||||||
{
|
{
|
||||||
std::string soName = tgt->GetSOName(this->Config);
|
std::string soName = tgt->GetSOName(this->Config);
|
||||||
const char* soname = soName.empty()? 0 : soName.c_str();
|
const char* soname = soName.empty()? 0 : soName.c_str();
|
||||||
this->OrderDependentRPath->AddLibrary(lib, soname);
|
order->AddRuntimeLibrary(lib, soname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->OrderDependentRPath->AddLibrary(lib);
|
order->AddRuntimeLibrary(lib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -747,7 +806,8 @@ void cmComputeLinkInformation::ComputeItemParserInfo()
|
||||||
// Create regex to remove any library extension.
|
// Create regex to remove any library extension.
|
||||||
std::string reg("(.*)");
|
std::string reg("(.*)");
|
||||||
reg += libext;
|
reg += libext;
|
||||||
this->RemoveLibraryExtension.compile(reg.c_str());
|
this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions,
|
||||||
|
reg);
|
||||||
|
|
||||||
// Create a regex to match a library name. Match index 1 will be
|
// Create a regex to match a library name. Match index 1 will be
|
||||||
// the prefix if it exists and empty otherwise. Match index 2 will
|
// the prefix if it exists and empty otherwise. Match index 2 will
|
||||||
|
@ -913,18 +973,26 @@ void cmComputeLinkInformation::AddTargetItem(std::string const& item,
|
||||||
this->SetCurrentLinkType(LinkShared);
|
this->SetCurrentLinkType(LinkShared);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this platform wants a flag before the full path, add it.
|
|
||||||
if(!this->LibLinkFileFlag.empty())
|
|
||||||
{
|
|
||||||
this->Items.push_back(Item(this->LibLinkFileFlag, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep track of shared library targets linked.
|
// Keep track of shared library targets linked.
|
||||||
if(target->GetType() == cmTarget::SHARED_LIBRARY)
|
if(target->GetType() == cmTarget::SHARED_LIBRARY)
|
||||||
{
|
{
|
||||||
this->SharedLibrariesLinked.insert(target);
|
this->SharedLibrariesLinked.insert(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle case of an imported shared library with no soname.
|
||||||
|
if(this->NoSONameUsesPath &&
|
||||||
|
target->IsImportedSharedLibWithoutSOName(this->Config))
|
||||||
|
{
|
||||||
|
this->AddSharedLibNoSOName(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this platform wants a flag before the full path, add it.
|
||||||
|
if(!this->LibLinkFileFlag.empty())
|
||||||
|
{
|
||||||
|
this->Items.push_back(Item(this->LibLinkFileFlag, false));
|
||||||
|
}
|
||||||
|
|
||||||
// Now add the full path to the library.
|
// Now add the full path to the library.
|
||||||
this->Items.push_back(Item(item, true));
|
this->Items.push_back(Item(item, true));
|
||||||
}
|
}
|
||||||
|
@ -938,6 +1006,12 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for case of shared library with no builtin soname.
|
||||||
|
if(this->NoSONameUsesPath && this->CheckSharedLibNoSOName(item))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// This is called to handle a link item that is a full path.
|
// This is called to handle a link item that is a full path.
|
||||||
// If the target is not a static library make sure the link type is
|
// If the target is not a static library make sure the link type is
|
||||||
// shared. This is because dynamic-mode linking can handle both
|
// shared. This is because dynamic-mode linking can handle both
|
||||||
|
@ -959,11 +1033,11 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the directory in which the library appears because CMake
|
// For compatibility with CMake 2.4 include the item's directory in
|
||||||
// 2.4 in below added these as -L paths.
|
// the linker search path.
|
||||||
if(this->OldLinkDirMode)
|
if(this->OldLinkDirMode)
|
||||||
{
|
{
|
||||||
this->OldLinkDirs.push_back(cmSystemTools::GetFilenamePath(item));
|
this->OldLinkDirItems.push_back(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this platform wants a flag before the full path, add it.
|
// If this platform wants a flag before the full path, add it.
|
||||||
|
@ -1184,55 +1258,47 @@ void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
|
bool cmComputeLinkInformation::CheckSharedLibNoSOName(std::string const& item)
|
||||||
{
|
{
|
||||||
// Some search paths should never be emitted.
|
// This platform will use the path to a library as its soname if the
|
||||||
this->DirectoriesEmmitted = this->ImplicitLinkDirs;
|
// library is given via path and was not built with an soname. If
|
||||||
this->DirectoriesEmmitted.insert("");
|
// this is a shared library that might be the case. TODO: Check if
|
||||||
|
// the lib is a symlink to detect that it actually has an soname.
|
||||||
// Check if we need to include the runtime search path at link time.
|
std::string file = cmSystemTools::GetFilenameName(item);
|
||||||
std::string var = "CMAKE_SHARED_LIBRARY_LINK_";
|
if(this->ExtractSharedLibraryName.find(file))
|
||||||
var += this->LinkLanguage;
|
|
||||||
var += "_WITH_RUNTIME_PATH";
|
|
||||||
if(this->Makefile->IsOn(var.c_str()))
|
|
||||||
{
|
{
|
||||||
// This platform requires the runtime library path for shared
|
this->AddSharedLibNoSOName(item);
|
||||||
// libraries to be specified at link time as -L paths. It needs
|
return true;
|
||||||
// them so that transitive dependencies of the libraries linked
|
|
||||||
// may be found by the linker.
|
|
||||||
this->AddLinkerSearchDirectories(this->GetRuntimeSearchPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the search path entries requested by the user.
|
|
||||||
this->AddLinkerSearchDirectories(this->Target->GetLinkDirectories());
|
|
||||||
|
|
||||||
// Support broken projects if necessary.
|
|
||||||
if(this->HaveUserFlagItem && this->OldLinkDirMode)
|
|
||||||
{
|
|
||||||
this->AddLinkerSearchDirectories(this->OldLinkDirs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no separate linker runtime search flag (-rpath-link)
|
|
||||||
// and we have a search path for dependent libraries add it to the
|
|
||||||
// link directories.
|
|
||||||
if(this->OrderDependentRPath && this->RPathLinkFlag.empty())
|
|
||||||
{
|
|
||||||
this->AddLinkerSearchDirectories
|
|
||||||
(this->OrderDependentRPath->GetRuntimePath());
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void
|
void cmComputeLinkInformation::AddSharedLibNoSOName(std::string const& item)
|
||||||
cmComputeLinkInformation
|
|
||||||
::AddLinkerSearchDirectories(std::vector<std::string> const& dirs)
|
|
||||||
{
|
{
|
||||||
for(std::vector<std::string>::const_iterator i = dirs.begin();
|
// We have a full path to a shared library with no soname. We need
|
||||||
i != dirs.end(); ++i)
|
// to ask the linker to locate the item because otherwise the path
|
||||||
|
// we give to it will be embedded in the target linked. Then at
|
||||||
|
// runtime the dynamic linker will search for the library using the
|
||||||
|
// path instead of just the name.
|
||||||
|
std::string file = cmSystemTools::GetFilenameName(item);
|
||||||
|
this->AddUserItem(file);
|
||||||
|
|
||||||
|
// Make sure the link directory ordering will find the library.
|
||||||
|
this->OrderLinkerSearchPath->AddLinkLibrary(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmComputeLinkInformation::FinishLinkerSearchDirectories()
|
||||||
|
{
|
||||||
|
// Support broken projects if necessary.
|
||||||
|
if(this->HaveUserFlagItem && this->OldLinkDirMode)
|
||||||
{
|
{
|
||||||
if(this->DirectoriesEmmitted.insert(*i).second)
|
for(std::vector<std::string>::const_iterator
|
||||||
|
i = this->OldLinkDirItems.begin();
|
||||||
|
i != this->OldLinkDirItems.end(); ++i)
|
||||||
{
|
{
|
||||||
this->Directories.push_back(*i);
|
this->OrderLinkerSearchPath->AddLinkLibrary(*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1241,7 +1307,7 @@ cmComputeLinkInformation
|
||||||
std::vector<std::string> const&
|
std::vector<std::string> const&
|
||||||
cmComputeLinkInformation::GetRuntimeSearchPath()
|
cmComputeLinkInformation::GetRuntimeSearchPath()
|
||||||
{
|
{
|
||||||
return this->OrderRuntimeSearchPath->GetRuntimePath();
|
return this->OrderRuntimeSearchPath->GetOrderedDirectories();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -1261,7 +1327,11 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
|
||||||
const char* soname = soName.empty()? 0 : soName.c_str();
|
const char* soname = soName.empty()? 0 : soName.c_str();
|
||||||
|
|
||||||
// Include this library in the runtime path ordering.
|
// Include this library in the runtime path ordering.
|
||||||
this->OrderRuntimeSearchPath->AddLibrary(fullPath, soname);
|
this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath, soname);
|
||||||
|
if(this->LinkWithRuntimePath)
|
||||||
|
{
|
||||||
|
this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath, soname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -1289,7 +1359,11 @@ cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include this library in the runtime path ordering.
|
// Include this library in the runtime path ordering.
|
||||||
this->OrderRuntimeSearchPath->AddLibrary(fullPath);
|
this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
|
||||||
|
if(this->LinkWithRuntimePath)
|
||||||
|
{
|
||||||
|
this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -26,7 +26,7 @@ class cmGlobalGenerator;
|
||||||
class cmLocalGenerator;
|
class cmLocalGenerator;
|
||||||
class cmMakefile;
|
class cmMakefile;
|
||||||
class cmTarget;
|
class cmTarget;
|
||||||
class cmOrderRuntimeDirectories;
|
class cmOrderDirectories;
|
||||||
|
|
||||||
/** \class cmComputeLinkInformation
|
/** \class cmComputeLinkInformation
|
||||||
* \brief Compute link information for a target in one configuration.
|
* \brief Compute link information for a target in one configuration.
|
||||||
|
@ -89,9 +89,10 @@ private:
|
||||||
// Modes for dealing with dependent shared libraries.
|
// Modes for dealing with dependent shared libraries.
|
||||||
enum SharedDepMode
|
enum SharedDepMode
|
||||||
{
|
{
|
||||||
SharedDepModeNone, // Drop
|
SharedDepModeNone, // Drop
|
||||||
SharedDepModeDir, // Use in runtime information
|
SharedDepModeDir, // List dir in -rpath-link flag
|
||||||
SharedDepModeLink // List file on link line
|
SharedDepModeLibDir, // List dir in linker search path
|
||||||
|
SharedDepModeLink // List file on link line
|
||||||
};
|
};
|
||||||
|
|
||||||
// System info.
|
// System info.
|
||||||
|
@ -104,6 +105,8 @@ private:
|
||||||
std::string RuntimeSep;
|
std::string RuntimeSep;
|
||||||
std::string RuntimeAlways;
|
std::string RuntimeAlways;
|
||||||
bool RuntimeUseChrpath;
|
bool RuntimeUseChrpath;
|
||||||
|
bool NoSONameUsesPath;
|
||||||
|
bool LinkWithRuntimePath;
|
||||||
std::string RPathLinkFlag;
|
std::string RPathLinkFlag;
|
||||||
SharedDepMode SharedDependencyMode;
|
SharedDepMode SharedDependencyMode;
|
||||||
|
|
||||||
|
@ -124,7 +127,6 @@ private:
|
||||||
std::vector<std::string> SharedLinkExtensions;
|
std::vector<std::string> SharedLinkExtensions;
|
||||||
std::vector<std::string> LinkExtensions;
|
std::vector<std::string> LinkExtensions;
|
||||||
std::set<cmStdString> LinkPrefixes;
|
std::set<cmStdString> LinkPrefixes;
|
||||||
cmsys::RegularExpression RemoveLibraryExtension;
|
|
||||||
cmsys::RegularExpression ExtractStaticLibraryName;
|
cmsys::RegularExpression ExtractStaticLibraryName;
|
||||||
cmsys::RegularExpression ExtractSharedLibraryName;
|
cmsys::RegularExpression ExtractSharedLibraryName;
|
||||||
cmsys::RegularExpression ExtractAnyLibraryName;
|
cmsys::RegularExpression ExtractAnyLibraryName;
|
||||||
|
@ -133,7 +135,7 @@ private:
|
||||||
std::string CreateExtensionRegex(std::vector<std::string> const& exts);
|
std::string CreateExtensionRegex(std::vector<std::string> const& exts);
|
||||||
std::string NoCaseExpression(const char* str);
|
std::string NoCaseExpression(const char* str);
|
||||||
|
|
||||||
// Handling of link items that are not targets or full file paths.
|
// Handling of link items.
|
||||||
void AddTargetItem(std::string const& item, cmTarget* target);
|
void AddTargetItem(std::string const& item, cmTarget* target);
|
||||||
void AddFullItem(std::string const& item);
|
void AddFullItem(std::string const& item);
|
||||||
bool CheckImplicitDirItem(std::string const& item);
|
bool CheckImplicitDirItem(std::string const& item);
|
||||||
|
@ -141,6 +143,8 @@ private:
|
||||||
void AddDirectoryItem(std::string const& item);
|
void AddDirectoryItem(std::string const& item);
|
||||||
void AddFrameworkItem(std::string const& item);
|
void AddFrameworkItem(std::string const& item);
|
||||||
void DropDirectoryItem(std::string const& item);
|
void DropDirectoryItem(std::string const& item);
|
||||||
|
bool CheckSharedLibNoSOName(std::string const& item);
|
||||||
|
void AddSharedLibNoSOName(std::string const& item);
|
||||||
|
|
||||||
// Framework info.
|
// Framework info.
|
||||||
void ComputeFrameworkInfo();
|
void ComputeFrameworkInfo();
|
||||||
|
@ -149,23 +153,22 @@ private:
|
||||||
cmsys::RegularExpression SplitFramework;
|
cmsys::RegularExpression SplitFramework;
|
||||||
|
|
||||||
// Linker search path computation.
|
// Linker search path computation.
|
||||||
void ComputeLinkerSearchDirectories();
|
cmOrderDirectories* OrderLinkerSearchPath;
|
||||||
void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
|
void FinishLinkerSearchDirectories();
|
||||||
std::set<cmStdString> DirectoriesEmmitted;
|
|
||||||
std::set<cmStdString> ImplicitLinkDirs;
|
std::set<cmStdString> ImplicitLinkDirs;
|
||||||
|
|
||||||
// Linker search path compatibility mode.
|
// Linker search path compatibility mode.
|
||||||
std::vector<std::string> OldLinkDirs;
|
std::vector<std::string> OldLinkDirItems;
|
||||||
bool OldLinkDirMode;
|
bool OldLinkDirMode;
|
||||||
bool HaveUserFlagItem;
|
bool HaveUserFlagItem;
|
||||||
|
|
||||||
// Runtime path computation.
|
// Runtime path computation.
|
||||||
cmOrderRuntimeDirectories* OrderRuntimeSearchPath;
|
cmOrderDirectories* OrderRuntimeSearchPath;
|
||||||
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);
|
||||||
|
|
||||||
// Dependent library path computation.
|
// Dependent library path computation.
|
||||||
cmOrderRuntimeDirectories* OrderDependentRPath;
|
cmOrderDirectories* OrderDependentRPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,524 @@
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Program: CMake - Cross-Platform Makefile Generator
|
||||||
|
Module: $RCSfile$
|
||||||
|
Language: C++
|
||||||
|
Date: $Date$
|
||||||
|
Version: $Revision$
|
||||||
|
|
||||||
|
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
||||||
|
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the above copyright notices for more information.
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
#include "cmOrderDirectories.h"
|
||||||
|
|
||||||
|
#include "cmGlobalGenerator.h"
|
||||||
|
#include "cmSystemTools.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Directory ordering computation.
|
||||||
|
- Useful to compute a safe runtime library path order
|
||||||
|
- Need runtime path for supporting INSTALL_RPATH_USE_LINK_PATH
|
||||||
|
- Need runtime path at link time to pickup transitive link dependencies
|
||||||
|
for shared libraries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
class cmOrderDirectoriesConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmOrderDirectoriesConstraint(cmOrderDirectories* od,
|
||||||
|
std::string const& file):
|
||||||
|
OD(od), GlobalGenerator(od->GlobalGenerator)
|
||||||
|
{
|
||||||
|
this->FullPath = file;
|
||||||
|
this->Directory = cmSystemTools::GetFilenamePath(file);
|
||||||
|
this->FileName = cmSystemTools::GetFilenameName(file);
|
||||||
|
}
|
||||||
|
virtual ~cmOrderDirectoriesConstraint() {}
|
||||||
|
|
||||||
|
void AddDirectory()
|
||||||
|
{
|
||||||
|
this->DirectoryIndex = this->OD->AddOriginalDirectory(this->Directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Report(std::ostream& e) = 0;
|
||||||
|
|
||||||
|
void FindConflicts(unsigned int index)
|
||||||
|
{
|
||||||
|
for(unsigned int i=0; i < this->OD->OriginalDirectories.size(); ++i)
|
||||||
|
{
|
||||||
|
// Check if this directory conflicts with they entry.
|
||||||
|
std::string const& dir = this->OD->OriginalDirectories[i];
|
||||||
|
if(dir != this->Directory && this->FindConflict(dir))
|
||||||
|
{
|
||||||
|
// The library will be found in this directory but this is not
|
||||||
|
// the directory named for it. Add an entry to make sure the
|
||||||
|
// desired directory comes before this one.
|
||||||
|
cmOrderDirectories::ConflictPair p(this->DirectoryIndex, index);
|
||||||
|
this->OD->ConflictGraph[i].push_back(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
virtual bool FindConflict(std::string const& dir) = 0;
|
||||||
|
|
||||||
|
bool FileMayConflict(std::string const& dir, std::string const& name);
|
||||||
|
|
||||||
|
cmOrderDirectories* OD;
|
||||||
|
cmGlobalGenerator* GlobalGenerator;
|
||||||
|
|
||||||
|
// The location in which the item is supposed to be found.
|
||||||
|
std::string FullPath;
|
||||||
|
std::string Directory;
|
||||||
|
std::string FileName;
|
||||||
|
|
||||||
|
// The index assigned to the directory.
|
||||||
|
int DirectoryIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool cmOrderDirectoriesConstraint::FileMayConflict(std::string const& dir,
|
||||||
|
std::string const& name)
|
||||||
|
{
|
||||||
|
// Check if the file will be built by cmake.
|
||||||
|
std::set<cmStdString> const& files =
|
||||||
|
(this->GlobalGenerator->GetDirectoryContent(dir, false));
|
||||||
|
if(std::set<cmStdString>::const_iterator(files.find(name)) != files.end())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the file exists on disk and is not a symlink back to the
|
||||||
|
// original file.
|
||||||
|
std::string file = dir;
|
||||||
|
file += "/";
|
||||||
|
file += name;
|
||||||
|
if(cmSystemTools::FileExists(file.c_str(), true) &&
|
||||||
|
!cmSystemTools::SameFile(this->FullPath.c_str(), file.c_str()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
class cmOrderDirectoriesConstraintSOName: public cmOrderDirectoriesConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmOrderDirectoriesConstraintSOName(cmOrderDirectories* od,
|
||||||
|
std::string const& file,
|
||||||
|
const char* soname):
|
||||||
|
cmOrderDirectoriesConstraint(od, file), SOName(soname? soname : "")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Report(std::ostream& e)
|
||||||
|
{
|
||||||
|
e << "runtime library [";
|
||||||
|
if(this->SOName.empty())
|
||||||
|
{
|
||||||
|
e << this->FileName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e << this->SOName;
|
||||||
|
}
|
||||||
|
e << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool FindConflict(std::string const& dir);
|
||||||
|
private:
|
||||||
|
// The soname of the shared library if it is known.
|
||||||
|
std::string SOName;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool cmOrderDirectoriesConstraintSOName::FindConflict(std::string const& dir)
|
||||||
|
{
|
||||||
|
// Determine which type of check to do.
|
||||||
|
if(!this->SOName.empty())
|
||||||
|
{
|
||||||
|
// We have the library soname. Check if it will be found.
|
||||||
|
if(this->FileMayConflict(dir, this->SOName))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We do not have the soname. Look for files in the directory
|
||||||
|
// that may conflict.
|
||||||
|
std::set<cmStdString> const& files =
|
||||||
|
(this->GlobalGenerator
|
||||||
|
->GetDirectoryContent(dir, true));
|
||||||
|
|
||||||
|
// Get the set of files that might conflict. Since we do not
|
||||||
|
// know the soname just look at all files that start with the
|
||||||
|
// file name. Usually the soname starts with the library name.
|
||||||
|
// TODO: Check if the library is a symlink and guess the soname.
|
||||||
|
std::string base = this->FileName;
|
||||||
|
std::set<cmStdString>::const_iterator first = files.lower_bound(base);
|
||||||
|
++base[base.size()-1];
|
||||||
|
std::set<cmStdString>::const_iterator last = files.upper_bound(base);
|
||||||
|
bool found = false;
|
||||||
|
for(std::set<cmStdString>::const_iterator fi = first; fi != last; ++fi)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
class cmOrderDirectoriesConstraintLibrary: public cmOrderDirectoriesConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmOrderDirectoriesConstraintLibrary(cmOrderDirectories* od,
|
||||||
|
std::string const& file):
|
||||||
|
cmOrderDirectoriesConstraint(od, file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Report(std::ostream& e)
|
||||||
|
{
|
||||||
|
e << "link library [" << this->FileName << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool FindConflict(std::string const& dir);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool cmOrderDirectoriesConstraintLibrary::FindConflict(std::string const& dir)
|
||||||
|
{
|
||||||
|
// We have the library file name. Check if it will be found.
|
||||||
|
if(this->FileMayConflict(dir, this->FileName))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check if the file exists with other extensions the linker
|
||||||
|
// might consider.
|
||||||
|
if(!this->OD->LinkExtensions.empty() &&
|
||||||
|
this->OD->RemoveLibraryExtension.find(this->FileName))
|
||||||
|
{
|
||||||
|
cmStdString lib = this->OD->RemoveLibraryExtension.match(1);
|
||||||
|
cmStdString ext = this->OD->RemoveLibraryExtension.match(2);
|
||||||
|
for(std::vector<std::string>::iterator
|
||||||
|
i = this->OD->LinkExtensions.begin();
|
||||||
|
i != this->OD->LinkExtensions.end(); ++i)
|
||||||
|
{
|
||||||
|
if(*i != ext)
|
||||||
|
{
|
||||||
|
std::string fname = lib;
|
||||||
|
fname += *i;
|
||||||
|
if(this->FileMayConflict(dir, fname.c_str()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmOrderDirectories::cmOrderDirectories(cmGlobalGenerator* gg,
|
||||||
|
const char* name,
|
||||||
|
const char* purpose)
|
||||||
|
{
|
||||||
|
this->GlobalGenerator = gg;
|
||||||
|
this->Name = name;
|
||||||
|
this->Purpose = purpose;
|
||||||
|
this->Computed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmOrderDirectories::~cmOrderDirectories()
|
||||||
|
{
|
||||||
|
for(std::vector<cmOrderDirectoriesConstraint*>::iterator
|
||||||
|
i = this->ConstraintEntries.begin();
|
||||||
|
i != this->ConstraintEntries.end(); ++i)
|
||||||
|
{
|
||||||
|
delete *i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::vector<std::string> const& cmOrderDirectories::GetOrderedDirectories()
|
||||||
|
{
|
||||||
|
if(!this->Computed)
|
||||||
|
{
|
||||||
|
this->Computed = true;
|
||||||
|
this->CollectOriginalDirectories();
|
||||||
|
this->FindConflicts();
|
||||||
|
this->OrderDirectories();
|
||||||
|
}
|
||||||
|
return this->OrderedDirectories;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath,
|
||||||
|
const char* soname)
|
||||||
|
{
|
||||||
|
// Add the runtime library at most once.
|
||||||
|
if(this->EmmittedConstraintSOName.insert(fullPath).second)
|
||||||
|
{
|
||||||
|
// Avoid dealing with implicit directories.
|
||||||
|
if(!this->ImplicitDirectories.empty())
|
||||||
|
{
|
||||||
|
std::string dir = cmSystemTools::GetFilenamePath(fullPath);
|
||||||
|
if(this->ImplicitDirectories.find(dir) !=
|
||||||
|
this->ImplicitDirectories.end())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the runtime information entry for this library.
|
||||||
|
this->ConstraintEntries.push_back(
|
||||||
|
new cmOrderDirectoriesConstraintSOName(this, fullPath, soname));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This can happen if the same library is linked multiple times.
|
||||||
|
// In that case the runtime information check need be done only
|
||||||
|
// once anyway. For shared libs we could add a check in AddItem
|
||||||
|
// to not repeat them.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmOrderDirectories::AddLinkLibrary(std::string const& fullPath)
|
||||||
|
{
|
||||||
|
// Link extension info is required for library constraints.
|
||||||
|
assert(!this->LinkExtensions.empty());
|
||||||
|
|
||||||
|
// Add the link library at most once.
|
||||||
|
if(this->EmmittedConstraintLibrary.insert(fullPath).second)
|
||||||
|
{
|
||||||
|
// Avoid dealing with implicit directories.
|
||||||
|
if(!this->ImplicitDirectories.empty())
|
||||||
|
{
|
||||||
|
std::string dir = cmSystemTools::GetFilenamePath(fullPath);
|
||||||
|
if(this->ImplicitDirectories.find(dir) !=
|
||||||
|
this->ImplicitDirectories.end())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the link library entry.
|
||||||
|
this->ConstraintEntries.push_back(
|
||||||
|
new cmOrderDirectoriesConstraintLibrary(this, fullPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
cmOrderDirectories
|
||||||
|
::AddUserDirectories(std::vector<std::string> const& extra)
|
||||||
|
{
|
||||||
|
this->UserDirectories.insert(this->UserDirectories.end(),
|
||||||
|
extra.begin(), extra.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
cmOrderDirectories
|
||||||
|
::SetImplicitDirectories(std::set<cmStdString> const& implicitDirs)
|
||||||
|
{
|
||||||
|
this->ImplicitDirectories = implicitDirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
cmOrderDirectories
|
||||||
|
::SetLinkExtensionInfo(std::vector<std::string> const& linkExtensions,
|
||||||
|
std::string const& removeExtRegex)
|
||||||
|
{
|
||||||
|
this->LinkExtensions = linkExtensions;
|
||||||
|
this->RemoveLibraryExtension.compile(removeExtRegex.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmOrderDirectories::CollectOriginalDirectories()
|
||||||
|
{
|
||||||
|
// Add user directories specified for inclusion. These should be
|
||||||
|
// indexed first so their original order is preserved as much as
|
||||||
|
// possible subject to the constraints.
|
||||||
|
for(std::vector<std::string>::const_iterator
|
||||||
|
di = this->UserDirectories.begin();
|
||||||
|
di != this->UserDirectories.end(); ++di)
|
||||||
|
{
|
||||||
|
// Avoid dealing with implicit directories.
|
||||||
|
if(this->ImplicitDirectories.find(*di) !=
|
||||||
|
this->ImplicitDirectories.end())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the empty string.
|
||||||
|
if(di->empty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this directory.
|
||||||
|
this->AddOriginalDirectory(*di);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add directories containing constraints.
|
||||||
|
for(unsigned int i=0; i < this->ConstraintEntries.size(); ++i)
|
||||||
|
{
|
||||||
|
this->ConstraintEntries[i]->AddDirectory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
int cmOrderDirectories::AddOriginalDirectory(std::string const& dir)
|
||||||
|
{
|
||||||
|
// Add the runtime directory with a unique index.
|
||||||
|
std::map<cmStdString, int>::iterator i =
|
||||||
|
this->DirectoryIndex.find(dir);
|
||||||
|
if(i == this->DirectoryIndex.end())
|
||||||
|
{
|
||||||
|
std::map<cmStdString, int>::value_type
|
||||||
|
entry(dir, static_cast<int>(this->OriginalDirectories.size()));
|
||||||
|
i = this->DirectoryIndex.insert(entry).first;
|
||||||
|
this->OriginalDirectories.push_back(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct cmOrderDirectoriesCompare
|
||||||
|
{
|
||||||
|
typedef std::pair<int, int> ConflictPair;
|
||||||
|
|
||||||
|
// The conflict pair is unique based on just the directory
|
||||||
|
// (first). The second element is only used for displaying
|
||||||
|
// information about why the entry is present.
|
||||||
|
bool operator()(ConflictPair const& l,
|
||||||
|
ConflictPair const& r)
|
||||||
|
{
|
||||||
|
return l.first == r.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmOrderDirectories::FindConflicts()
|
||||||
|
{
|
||||||
|
// Allocate the conflict graph.
|
||||||
|
this->ConflictGraph.resize(this->OriginalDirectories.size());
|
||||||
|
this->DirectoryVisited.resize(this->OriginalDirectories.size(), 0);
|
||||||
|
|
||||||
|
// Find directories conflicting with each entry.
|
||||||
|
for(unsigned int i=0; i < this->ConstraintEntries.size(); ++i)
|
||||||
|
{
|
||||||
|
this->ConstraintEntries[i]->FindConflicts(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up the conflict graph representation.
|
||||||
|
for(std::vector<ConflictList>::iterator
|
||||||
|
i = this->ConflictGraph.begin();
|
||||||
|
i != this->ConflictGraph.end(); ++i)
|
||||||
|
{
|
||||||
|
// Sort the outgoing edges for each graph node so that the
|
||||||
|
// original order will be preserved as much as possible.
|
||||||
|
std::sort(i->begin(), i->end());
|
||||||
|
|
||||||
|
// Make the edge list unique so cycle detection will be reliable.
|
||||||
|
ConflictList::iterator last =
|
||||||
|
std::unique(i->begin(), i->end(), cmOrderDirectoriesCompare());
|
||||||
|
i->erase(last, i->end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmOrderDirectories::OrderDirectories()
|
||||||
|
{
|
||||||
|
// Allow a cycle to be diagnosed once.
|
||||||
|
this->CycleDiagnosed = false;
|
||||||
|
this->WalkId = 0;
|
||||||
|
|
||||||
|
// Iterate through the directories in the original order.
|
||||||
|
for(unsigned int i=0; i < this->OriginalDirectories.size(); ++i)
|
||||||
|
{
|
||||||
|
// Start a new DFS from this node.
|
||||||
|
++this->WalkId;
|
||||||
|
this->VisitDirectory(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmOrderDirectories::VisitDirectory(unsigned int i)
|
||||||
|
{
|
||||||
|
// Skip nodes already visited.
|
||||||
|
if(this->DirectoryVisited[i])
|
||||||
|
{
|
||||||
|
if(this->DirectoryVisited[i] == this->WalkId)
|
||||||
|
{
|
||||||
|
// We have reached a node previously visited on this DFS.
|
||||||
|
// There is a cycle.
|
||||||
|
this->DiagnoseCycle();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are now visiting this node so mark it.
|
||||||
|
this->DirectoryVisited[i] = this->WalkId;
|
||||||
|
|
||||||
|
// Visit the neighbors of the node first.
|
||||||
|
ConflictList const& clist = this->ConflictGraph[i];
|
||||||
|
for(ConflictList::const_iterator j = clist.begin();
|
||||||
|
j != clist.end(); ++j)
|
||||||
|
{
|
||||||
|
this->VisitDirectory(j->first);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that all directories required to come before this one have
|
||||||
|
// been emmitted, emit this directory.
|
||||||
|
this->OrderedDirectories.push_back(this->OriginalDirectories[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmOrderDirectories::DiagnoseCycle()
|
||||||
|
{
|
||||||
|
// Report the cycle at most once.
|
||||||
|
if(this->CycleDiagnosed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->CycleDiagnosed = true;
|
||||||
|
|
||||||
|
// Construct the message.
|
||||||
|
cmOStringStream e;
|
||||||
|
e << "WARNING: Cannot generate a safe " << this->Purpose
|
||||||
|
<< " for target " << this->Name
|
||||||
|
<< " because there is a cycle in the constraint graph:\n";
|
||||||
|
|
||||||
|
// Display the conflict graph.
|
||||||
|
for(unsigned int i=0; i < this->ConflictGraph.size(); ++i)
|
||||||
|
{
|
||||||
|
ConflictList const& clist = this->ConflictGraph[i];
|
||||||
|
e << "dir " << i << " is [" << this->OriginalDirectories[i] << "]\n";
|
||||||
|
for(ConflictList::const_iterator j = clist.begin();
|
||||||
|
j != clist.end(); ++j)
|
||||||
|
{
|
||||||
|
e << " dir " << j->first << " must precede it due to ";
|
||||||
|
this->ConstraintEntries[j->second]->Report(e);
|
||||||
|
e << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmSystemTools::Message(e.str().c_str());
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Program: CMake - Cross-Platform Makefile Generator
|
||||||
|
Module: $RCSfile$
|
||||||
|
Language: C++
|
||||||
|
Date: $Date$
|
||||||
|
Version: $Revision$
|
||||||
|
|
||||||
|
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
||||||
|
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the above copyright notices for more information.
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
#ifndef cmOrderDirectories_h
|
||||||
|
#define cmOrderDirectories_h
|
||||||
|
|
||||||
|
#include "cmStandardIncludes.h"
|
||||||
|
|
||||||
|
#include <cmsys/RegularExpression.hxx>
|
||||||
|
|
||||||
|
class cmGlobalGenerator;
|
||||||
|
class cmOrderDirectoriesConstraint;
|
||||||
|
class cmOrderDirectoriesConstraintLibrary;
|
||||||
|
|
||||||
|
/** \class cmOrderDirectories
|
||||||
|
* \brief Compute a safe runtime path order for a set of shared libraries.
|
||||||
|
*/
|
||||||
|
class cmOrderDirectories
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmOrderDirectories(cmGlobalGenerator* gg, const char* name,
|
||||||
|
const char* purpose);
|
||||||
|
~cmOrderDirectories();
|
||||||
|
void AddRuntimeLibrary(std::string const& fullPath, const char* soname = 0);
|
||||||
|
void AddLinkLibrary(std::string const& fullPath);
|
||||||
|
void AddUserDirectories(std::vector<std::string> const& extra);
|
||||||
|
void SetImplicitDirectories(std::set<cmStdString> const& implicitDirs);
|
||||||
|
void SetLinkExtensionInfo(std::vector<std::string> const& linkExtensions,
|
||||||
|
std::string const& removeExtRegex);
|
||||||
|
|
||||||
|
std::vector<std::string> const& GetOrderedDirectories();
|
||||||
|
private:
|
||||||
|
cmGlobalGenerator* GlobalGenerator;
|
||||||
|
std::string Name;
|
||||||
|
std::string Purpose;
|
||||||
|
|
||||||
|
bool Computed;
|
||||||
|
|
||||||
|
std::vector<std::string> OrderedDirectories;
|
||||||
|
|
||||||
|
bool OrderedDirectoriesComputed;
|
||||||
|
std::vector<cmOrderDirectoriesConstraint*> ConstraintEntries;
|
||||||
|
std::vector<std::string> UserDirectories;
|
||||||
|
cmsys::RegularExpression RemoveLibraryExtension;
|
||||||
|
std::vector<std::string> LinkExtensions;
|
||||||
|
std::set<cmStdString> ImplicitDirectories;
|
||||||
|
std::set<cmStdString> EmmittedConstraintSOName;
|
||||||
|
std::set<cmStdString> EmmittedConstraintLibrary;
|
||||||
|
std::vector<std::string> OriginalDirectories;
|
||||||
|
std::map<cmStdString, int> DirectoryIndex;
|
||||||
|
std::vector<int> DirectoryVisited;
|
||||||
|
void CollectOriginalDirectories();
|
||||||
|
int AddOriginalDirectory(std::string const& dir);
|
||||||
|
void FindConflicts();
|
||||||
|
void OrderDirectories();
|
||||||
|
void VisitDirectory(unsigned int i);
|
||||||
|
void DiagnoseCycle();
|
||||||
|
bool CycleDiagnosed;
|
||||||
|
int WalkId;
|
||||||
|
|
||||||
|
// Adjacency-list representation of runtime path ordering graph.
|
||||||
|
// This maps from directory to those that must come *before* it.
|
||||||
|
// Each entry that must come before is a pair. The first element is
|
||||||
|
// the index of the directory that must come first. The second
|
||||||
|
// element is the index of the runtime library that added the
|
||||||
|
// constraint.
|
||||||
|
typedef std::pair<int, int> ConflictPair;
|
||||||
|
struct ConflictList: public std::vector<ConflictPair> {};
|
||||||
|
std::vector<ConflictList> ConflictGraph;
|
||||||
|
|
||||||
|
friend class cmOrderDirectoriesConstraint;
|
||||||
|
friend class cmOrderDirectoriesConstraintLibrary;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,325 +0,0 @@
|
||||||
/*=========================================================================
|
|
||||||
|
|
||||||
Program: CMake - Cross-Platform Makefile Generator
|
|
||||||
Module: $RCSfile$
|
|
||||||
Language: C++
|
|
||||||
Date: $Date$
|
|
||||||
Version: $Revision$
|
|
||||||
|
|
||||||
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
|
||||||
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
|
||||||
|
|
||||||
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
||||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. See the above copyright notices for more information.
|
|
||||||
|
|
||||||
=========================================================================*/
|
|
||||||
#include "cmOrderRuntimeDirectories.h"
|
|
||||||
|
|
||||||
#include "cmGlobalGenerator.h"
|
|
||||||
#include "cmSystemTools.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
/*
|
|
||||||
Directory ordering computation.
|
|
||||||
- Useful to compute a safe runtime library path order
|
|
||||||
- Need runtime path for supporting INSTALL_RPATH_USE_LINK_PATH
|
|
||||||
- Need runtime path at link time to pickup transitive link dependencies
|
|
||||||
for shared libraries.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
cmOrderRuntimeDirectories::cmOrderRuntimeDirectories(cmGlobalGenerator* gg,
|
|
||||||
const char* name,
|
|
||||||
const char* purpose)
|
|
||||||
{
|
|
||||||
this->GlobalGenerator = gg;
|
|
||||||
this->Name = name;
|
|
||||||
this->Purpose = purpose;
|
|
||||||
this->Computed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
std::vector<std::string> const& cmOrderRuntimeDirectories::GetRuntimePath()
|
|
||||||
{
|
|
||||||
if(!this->Computed)
|
|
||||||
{
|
|
||||||
this->Computed = true;
|
|
||||||
this->CollectRuntimeDirectories();
|
|
||||||
this->FindConflictingLibraries();
|
|
||||||
this->OrderRuntimeSearchPath();
|
|
||||||
}
|
|
||||||
return this->RuntimeSearchPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmOrderRuntimeDirectories::AddLibrary(std::string const& fullPath,
|
|
||||||
const char* soname)
|
|
||||||
{
|
|
||||||
// Add the runtime information at most once.
|
|
||||||
if(this->LibraryRuntimeInfoEmmitted.insert(fullPath).second)
|
|
||||||
{
|
|
||||||
// Construct the runtime information entry for this library.
|
|
||||||
LibraryRuntimeEntry entry;
|
|
||||||
entry.FileName = cmSystemTools::GetFilenameName(fullPath);
|
|
||||||
entry.SOName = soname? soname : "";
|
|
||||||
entry.Directory = cmSystemTools::GetFilenamePath(fullPath);
|
|
||||||
this->LibraryRuntimeInfo.push_back(entry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This can happen if the same library is linked multiple times.
|
|
||||||
// In that case the runtime information check need be done only
|
|
||||||
// once anyway. For shared libs we could add a check in AddItem
|
|
||||||
// to not repeat them.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void
|
|
||||||
cmOrderRuntimeDirectories
|
|
||||||
::AddDirectories(std::vector<std::string> const& extra)
|
|
||||||
{
|
|
||||||
this->UserDirectories.insert(this->UserDirectories.end(),
|
|
||||||
extra.begin(), extra.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmOrderRuntimeDirectories::CollectRuntimeDirectories()
|
|
||||||
{
|
|
||||||
// Get all directories that should be in the runtime search path.
|
|
||||||
|
|
||||||
// Add directories containing libraries.
|
|
||||||
for(std::vector<LibraryRuntimeEntry>::iterator
|
|
||||||
ei = this->LibraryRuntimeInfo.begin();
|
|
||||||
ei != this->LibraryRuntimeInfo.end(); ++ei)
|
|
||||||
{
|
|
||||||
ei->DirectoryIndex = this->AddRuntimeDirectory(ei->Directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add link directories specified for inclusion.
|
|
||||||
for(std::vector<std::string>::const_iterator
|
|
||||||
di = this->UserDirectories.begin();
|
|
||||||
di != this->UserDirectories.end(); ++di)
|
|
||||||
{
|
|
||||||
this->AddRuntimeDirectory(*di);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int cmOrderRuntimeDirectories::AddRuntimeDirectory(std::string const& dir)
|
|
||||||
{
|
|
||||||
// Add the runtime directory with a unique index.
|
|
||||||
std::map<cmStdString, int>::iterator i =
|
|
||||||
this->RuntimeDirectoryIndex.find(dir);
|
|
||||||
if(i == this->RuntimeDirectoryIndex.end())
|
|
||||||
{
|
|
||||||
std::map<cmStdString, int>::value_type
|
|
||||||
entry(dir, static_cast<int>(this->RuntimeDirectories.size()));
|
|
||||||
i = this->RuntimeDirectoryIndex.insert(entry).first;
|
|
||||||
this->RuntimeDirectories.push_back(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return i->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
struct cmOrderRuntimeDirectoriesCompare
|
|
||||||
{
|
|
||||||
typedef std::pair<int, int> RuntimeConflictPair;
|
|
||||||
|
|
||||||
// The conflict pair is unique based on just the directory
|
|
||||||
// (first). The second element is only used for displaying
|
|
||||||
// information about why the entry is present.
|
|
||||||
bool operator()(RuntimeConflictPair const& l,
|
|
||||||
RuntimeConflictPair const& r)
|
|
||||||
{
|
|
||||||
return l.first == r.first;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmOrderRuntimeDirectories::FindConflictingLibraries()
|
|
||||||
{
|
|
||||||
// Allocate the conflict graph.
|
|
||||||
this->RuntimeConflictGraph.resize(this->RuntimeDirectories.size());
|
|
||||||
this->RuntimeDirectoryVisited.resize(this->RuntimeDirectories.size(), 0);
|
|
||||||
|
|
||||||
// Find all runtime directories providing each library.
|
|
||||||
for(unsigned int lri = 0; lri < this->LibraryRuntimeInfo.size(); ++lri)
|
|
||||||
{
|
|
||||||
this->FindDirectoriesForLib(lri);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up the conflict graph representation.
|
|
||||||
for(std::vector<RuntimeConflictList>::iterator
|
|
||||||
i = this->RuntimeConflictGraph.begin();
|
|
||||||
i != this->RuntimeConflictGraph.end(); ++i)
|
|
||||||
{
|
|
||||||
// Sort the outgoing edges for each graph node so that the
|
|
||||||
// original order will be preserved as much as possible.
|
|
||||||
std::sort(i->begin(), i->end());
|
|
||||||
|
|
||||||
// Make the edge list unique so cycle detection will be reliable.
|
|
||||||
RuntimeConflictList::iterator last =
|
|
||||||
std::unique(i->begin(), i->end(), cmOrderRuntimeDirectoriesCompare());
|
|
||||||
i->erase(last, i->end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmOrderRuntimeDirectories::FindDirectoriesForLib(unsigned int lri)
|
|
||||||
{
|
|
||||||
// Search through the runtime directories to find those providing
|
|
||||||
// this library.
|
|
||||||
LibraryRuntimeEntry& re = this->LibraryRuntimeInfo[lri];
|
|
||||||
for(unsigned int i = 0; i < this->RuntimeDirectories.size(); ++i)
|
|
||||||
{
|
|
||||||
// Skip the directory that is supposed to provide the library.
|
|
||||||
if(this->RuntimeDirectories[i] == re.Directory)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine which type of check to do.
|
|
||||||
if(!re.SOName.empty())
|
|
||||||
{
|
|
||||||
// We have the library soname. Check if it will be found.
|
|
||||||
std::string file = this->RuntimeDirectories[i];
|
|
||||||
file += "/";
|
|
||||||
file += re.SOName;
|
|
||||||
std::set<cmStdString> const& files =
|
|
||||||
(this->GlobalGenerator
|
|
||||||
->GetDirectoryContent(this->RuntimeDirectories[i], false));
|
|
||||||
if((std::set<cmStdString>::const_iterator(files.find(re.SOName)) !=
|
|
||||||
files.end()) ||
|
|
||||||
cmSystemTools::FileExists(file.c_str(), true))
|
|
||||||
{
|
|
||||||
// The library will be found in this directory but this is not
|
|
||||||
// the directory named for it. Add an entry to make sure the
|
|
||||||
// desired directory comes before this one.
|
|
||||||
RuntimeConflictPair p(re.DirectoryIndex, lri);
|
|
||||||
this->RuntimeConflictGraph[i].push_back(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We do not have the soname. Look for files in the directory
|
|
||||||
// that may conflict.
|
|
||||||
std::set<cmStdString> const& files =
|
|
||||||
(this->GlobalGenerator
|
|
||||||
->GetDirectoryContent(this->RuntimeDirectories[i], true));
|
|
||||||
|
|
||||||
// Get the set of files that might conflict. Since we do not
|
|
||||||
// know the soname just look at all files that start with the
|
|
||||||
// file name. Usually the soname starts with the library name.
|
|
||||||
std::string base = re.FileName;
|
|
||||||
std::set<cmStdString>::const_iterator first = files.lower_bound(base);
|
|
||||||
++base[base.size()-1];
|
|
||||||
std::set<cmStdString>::const_iterator last = files.upper_bound(base);
|
|
||||||
bool found = false;
|
|
||||||
for(std::set<cmStdString>::const_iterator fi = first;
|
|
||||||
!found && fi != last; ++fi)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(found)
|
|
||||||
{
|
|
||||||
// The library may be found in this directory but this is not
|
|
||||||
// the directory named for it. Add an entry to make sure the
|
|
||||||
// desired directory comes before this one.
|
|
||||||
RuntimeConflictPair p(re.DirectoryIndex, lri);
|
|
||||||
this->RuntimeConflictGraph[i].push_back(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmOrderRuntimeDirectories::OrderRuntimeSearchPath()
|
|
||||||
{
|
|
||||||
// Allow a cycle to be diagnosed once.
|
|
||||||
this->CycleDiagnosed = false;
|
|
||||||
this->WalkId = 0;
|
|
||||||
|
|
||||||
// Iterate through the directories in the original order.
|
|
||||||
for(unsigned int i=0; i < this->RuntimeDirectories.size(); ++i)
|
|
||||||
{
|
|
||||||
// Start a new DFS from this node.
|
|
||||||
++this->WalkId;
|
|
||||||
this->VisitRuntimeDirectory(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmOrderRuntimeDirectories::VisitRuntimeDirectory(unsigned int i)
|
|
||||||
{
|
|
||||||
// Skip nodes already visited.
|
|
||||||
if(this->RuntimeDirectoryVisited[i])
|
|
||||||
{
|
|
||||||
if(this->RuntimeDirectoryVisited[i] == this->WalkId)
|
|
||||||
{
|
|
||||||
// We have reached a node previously visited on this DFS.
|
|
||||||
// There is a cycle.
|
|
||||||
this->DiagnoseCycle();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are now visiting this node so mark it.
|
|
||||||
this->RuntimeDirectoryVisited[i] = this->WalkId;
|
|
||||||
|
|
||||||
// Visit the neighbors of the node first.
|
|
||||||
RuntimeConflictList const& clist = this->RuntimeConflictGraph[i];
|
|
||||||
for(RuntimeConflictList::const_iterator j = clist.begin();
|
|
||||||
j != clist.end(); ++j)
|
|
||||||
{
|
|
||||||
this->VisitRuntimeDirectory(j->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that all directories required to come before this one have
|
|
||||||
// been emmitted, emit this directory.
|
|
||||||
this->RuntimeSearchPath.push_back(this->RuntimeDirectories[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmOrderRuntimeDirectories::DiagnoseCycle()
|
|
||||||
{
|
|
||||||
// Report the cycle at most once.
|
|
||||||
if(this->CycleDiagnosed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->CycleDiagnosed = true;
|
|
||||||
|
|
||||||
// Construct the message.
|
|
||||||
cmOStringStream e;
|
|
||||||
e << "WARNING: Cannot generate a safe " << this->Purpose
|
|
||||||
<< " for target " << this->Name
|
|
||||||
<< " because there is a cycle in the constraint graph:\n";
|
|
||||||
|
|
||||||
// Display the conflict graph.
|
|
||||||
for(unsigned int i=0; i < this->RuntimeConflictGraph.size(); ++i)
|
|
||||||
{
|
|
||||||
RuntimeConflictList const& clist = this->RuntimeConflictGraph[i];
|
|
||||||
e << "dir " << i << " is [" << this->RuntimeDirectories[i] << "]\n";
|
|
||||||
for(RuntimeConflictList::const_iterator j = clist.begin();
|
|
||||||
j != clist.end(); ++j)
|
|
||||||
{
|
|
||||||
e << " dir " << j->first << " must precede it due to [";
|
|
||||||
LibraryRuntimeEntry const& re = this->LibraryRuntimeInfo[j->second];
|
|
||||||
if(re.SOName.empty())
|
|
||||||
{
|
|
||||||
e << re.FileName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
e << re.SOName;
|
|
||||||
}
|
|
||||||
e << "]\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmSystemTools::Message(e.str().c_str());
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
/*=========================================================================
|
|
||||||
|
|
||||||
Program: CMake - Cross-Platform Makefile Generator
|
|
||||||
Module: $RCSfile$
|
|
||||||
Language: C++
|
|
||||||
Date: $Date$
|
|
||||||
Version: $Revision$
|
|
||||||
|
|
||||||
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
|
||||||
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
|
||||||
|
|
||||||
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
||||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. See the above copyright notices for more information.
|
|
||||||
|
|
||||||
=========================================================================*/
|
|
||||||
#ifndef cmOrderRuntimeDirectories_h
|
|
||||||
#define cmOrderRuntimeDirectories_h
|
|
||||||
|
|
||||||
#include "cmStandardIncludes.h"
|
|
||||||
|
|
||||||
class cmGlobalGenerator;
|
|
||||||
|
|
||||||
/** \class cmOrderRuntimeDirectories
|
|
||||||
* \brief Compute a safe runtime path order for a set of shared libraries.
|
|
||||||
*/
|
|
||||||
class cmOrderRuntimeDirectories
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cmOrderRuntimeDirectories(cmGlobalGenerator* gg, const char* name,
|
|
||||||
const char* purpose);
|
|
||||||
void AddLibrary(std::string const& fullPath, const char* soname = 0);
|
|
||||||
void AddDirectories(std::vector<std::string> const& extra);
|
|
||||||
|
|
||||||
std::vector<std::string> const& GetRuntimePath();
|
|
||||||
private:
|
|
||||||
cmGlobalGenerator* GlobalGenerator;
|
|
||||||
std::string Name;
|
|
||||||
std::string Purpose;
|
|
||||||
|
|
||||||
bool Computed;
|
|
||||||
|
|
||||||
std::vector<std::string> RuntimeSearchPath;
|
|
||||||
|
|
||||||
// Runtime path computation.
|
|
||||||
struct LibraryRuntimeEntry
|
|
||||||
{
|
|
||||||
// The file name of the library.
|
|
||||||
std::string FileName;
|
|
||||||
|
|
||||||
// The soname of the shared library if it is known.
|
|
||||||
std::string SOName;
|
|
||||||
|
|
||||||
// The directory in which the library is supposed to be found.
|
|
||||||
std::string Directory;
|
|
||||||
|
|
||||||
// The index assigned to the directory.
|
|
||||||
int DirectoryIndex;
|
|
||||||
};
|
|
||||||
bool RuntimeSearchPathComputed;
|
|
||||||
std::vector<LibraryRuntimeEntry> LibraryRuntimeInfo;
|
|
||||||
std::vector<std::string> UserDirectories;
|
|
||||||
std::set<cmStdString> LibraryRuntimeInfoEmmitted;
|
|
||||||
std::vector<std::string> RuntimeDirectories;
|
|
||||||
std::map<cmStdString, int> RuntimeDirectoryIndex;
|
|
||||||
std::vector<int> RuntimeDirectoryVisited;
|
|
||||||
void CollectRuntimeDirectories();
|
|
||||||
int AddRuntimeDirectory(std::string const& dir);
|
|
||||||
void FindConflictingLibraries();
|
|
||||||
void FindDirectoriesForLib(unsigned int lri);
|
|
||||||
void OrderRuntimeSearchPath();
|
|
||||||
void VisitRuntimeDirectory(unsigned int i);
|
|
||||||
void DiagnoseCycle();
|
|
||||||
bool CycleDiagnosed;
|
|
||||||
int WalkId;
|
|
||||||
|
|
||||||
// Adjacency-list representation of runtime path ordering graph.
|
|
||||||
// This maps from directory to those that must come *before* it.
|
|
||||||
// Each entry that must come before is a pair. The first element is
|
|
||||||
// the index of the directory that must come first. The second
|
|
||||||
// element is the index of the runtime library that added the
|
|
||||||
// constraint.
|
|
||||||
typedef std::pair<int, int> RuntimeConflictPair;
|
|
||||||
struct RuntimeConflictList: public std::vector<RuntimeConflictPair> {};
|
|
||||||
std::vector<RuntimeConflictList> RuntimeConflictGraph;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -2048,7 +2048,17 @@ std::string cmTarget::GetSOName(const char* config)
|
||||||
// Lookup the imported soname.
|
// Lookup the imported soname.
|
||||||
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
|
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
|
||||||
{
|
{
|
||||||
return info->SOName;
|
if(info->NoSOName)
|
||||||
|
{
|
||||||
|
// The imported library has no builtin soname so the name
|
||||||
|
// searched at runtime will be just the filename.
|
||||||
|
return cmSystemTools::GetFilenameName(info->Location);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use the soname given if any.
|
||||||
|
return info->SOName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2068,6 +2078,19 @@ std::string cmTarget::GetSOName(const char* config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool cmTarget::IsImportedSharedLibWithoutSOName(const char* config)
|
||||||
|
{
|
||||||
|
if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY)
|
||||||
|
{
|
||||||
|
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
|
||||||
|
{
|
||||||
|
return info->NoSOName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
std::string cmTarget::NormalGetRealName(const char* config)
|
std::string cmTarget::NormalGetRealName(const char* config)
|
||||||
{
|
{
|
||||||
|
@ -3054,6 +3077,9 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
|
||||||
// properties. The "IMPORTED_" namespace is reserved for properties
|
// properties. The "IMPORTED_" namespace is reserved for properties
|
||||||
// defined by the project exporting the target.
|
// defined by the project exporting the target.
|
||||||
|
|
||||||
|
// Initialize members.
|
||||||
|
info.NoSOName = false;
|
||||||
|
|
||||||
// Track the configuration-specific property suffix.
|
// Track the configuration-specific property suffix.
|
||||||
std::string suffix = "_";
|
std::string suffix = "_";
|
||||||
suffix += desired_config;
|
suffix += desired_config;
|
||||||
|
@ -3164,6 +3190,21 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the "no-soname" mark.
|
||||||
|
if(this->GetType() == cmTarget::SHARED_LIBRARY)
|
||||||
|
{
|
||||||
|
std::string soProp = "IMPORTED_NO_SONAME";
|
||||||
|
soProp += suffix;
|
||||||
|
if(const char* config_no_soname = this->GetProperty(soProp.c_str()))
|
||||||
|
{
|
||||||
|
info.NoSOName = cmSystemTools::IsOn(config_no_soname);
|
||||||
|
}
|
||||||
|
else if(const char* no_soname = this->GetProperty("IMPORTED_NO_SONAME"))
|
||||||
|
{
|
||||||
|
info.NoSOName = cmSystemTools::IsOn(no_soname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the import library.
|
// Get the import library.
|
||||||
if(this->GetType() == cmTarget::SHARED_LIBRARY ||
|
if(this->GetType() == cmTarget::SHARED_LIBRARY ||
|
||||||
this->IsExecutableWithExports())
|
this->IsExecutableWithExports())
|
||||||
|
|
|
@ -281,6 +281,10 @@ public:
|
||||||
/** Get the soname of the target. Allowed only for a shared library. */
|
/** Get the soname of the target. Allowed only for a shared library. */
|
||||||
std::string GetSOName(const char* config);
|
std::string GetSOName(const char* config);
|
||||||
|
|
||||||
|
/** Test for special case of a third-party shared library that has
|
||||||
|
no soname at all. */
|
||||||
|
bool IsImportedSharedLibWithoutSOName(const char* config);
|
||||||
|
|
||||||
/** Get the full path to the target according to the settings in its
|
/** Get the full path to the target according to the settings in its
|
||||||
makefile and the configuration type. */
|
makefile and the configuration type. */
|
||||||
std::string GetFullPath(const char* config=0, bool implib = false,
|
std::string GetFullPath(const char* config=0, bool implib = false,
|
||||||
|
@ -501,6 +505,7 @@ private:
|
||||||
// Cache import information from properties for each configuration.
|
// Cache import information from properties for each configuration.
|
||||||
struct ImportInfo
|
struct ImportInfo
|
||||||
{
|
{
|
||||||
|
bool NoSOName;
|
||||||
std::string Location;
|
std::string Location;
|
||||||
std::string SOName;
|
std::string SOName;
|
||||||
std::string ImportLibrary;
|
std::string ImportLibrary;
|
||||||
|
|
|
@ -175,7 +175,7 @@ CMAKE_CXX_SOURCES="\
|
||||||
cmListFileCache \
|
cmListFileCache \
|
||||||
cmComputeLinkDepends \
|
cmComputeLinkDepends \
|
||||||
cmComputeLinkInformation \
|
cmComputeLinkInformation \
|
||||||
cmOrderRuntimeDirectories \
|
cmOrderDirectories \
|
||||||
cmComputeTargetDepends \
|
cmComputeTargetDepends \
|
||||||
cmComputeComponentGraph \
|
cmComputeComponentGraph \
|
||||||
cmExprLexer \
|
cmExprLexer \
|
||||||
|
|
Loading…
Reference in New Issue