Commit 82fcaebe authored by Brad King's avatar Brad King
Browse files

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
parent f28f1585
......@@ -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.
*/
//----------------------------------------------------------------------------
......
This diff is collapsed.
......@@ -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();
......
/*=========================================================================
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);
}
}
//----------------------------------------------------------------------------