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

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();
......
This diff is collapsed.
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef cmOrderRuntimeDirectories_h
#define cmOrderRuntimeDirectories_h
#include "cmStandardIncludes.h"
class cmGlobalGenerator;
/** \class cmOrderRuntimeDirectories
* \brief Compute a safe runtime path order for a set of shared libraries.
*/
class cmOrderRuntimeDirectories
{
public:
cmOrderRuntimeDirectories(cmGlobalGenerator* gg, const char* name,
const char* purpose);
void AddLibrary(std::string const& fullPath, const char* soname = 0);
void AddDirectories(std::vector<std::string> const& extra);
std::vector<std::string> const& GetRuntimePath();
private:
cmGlobalGenerator* GlobalGenerator;
std::string Name;
std::string Purpose;
bool Computed;
std::vector<std::string> RuntimeSearchPath;
// Runtime path computation.
struct LibraryRuntimeEntry
{
// The file name of the library.
std::string FileName;
// The soname of the shared library if it is known.
std::string SOName;
// The directory in which the library is supposed to be found.
std::string Directory;
// The index assigned to the directory.
int DirectoryIndex;
};
bool RuntimeSearchPathComputed;
std::vector<LibraryRuntimeEntry> LibraryRuntimeInfo;
std::vector<std::string> UserDirectories;
std::set<cmStdString> LibraryRuntimeInfoEmmitted;
std::vector<std::string> RuntimeDirectories;
std::map<cmStdString, int> RuntimeDirectoryIndex;
std::vector<int> RuntimeDirectoryVisited;
void CollectRuntimeDirectories();
int AddRuntimeDirectory(std::string const& dir);
void FindConflictingLibraries();
void FindDirectoriesForLib(unsigned int lri);
void OrderRuntimeSearchPath();
void VisitRuntimeDirectory(unsigned int i);
void DiagnoseCycle();
bool CycleDiagnosed;
int WalkId;
// Adjacency-list representation of runtime path ordering graph.
// This maps from directory to those that must come *before* it.
// Each entry that must come before is a pair. The first element is
// the index of the directory that must come first. The second
// element is the index of the runtime library that added the
// constraint.
typedef std::pair<int, int> RuntimeConflictPair;
struct RuntimeConflictList: public std::vector<RuntimeConflictPair> {};
std::vector<RuntimeConflictList> RuntimeConflictGraph;
};
#endif
......@@ -193,13 +193,13 @@ void cmTarget::DefineProperties(cmake *cm)
"Shared libraries may be linked to other shared libraries as part "
"of their implementation. On some platforms the linker searches "
"for the dependent libraries of shared libraries they are including "
"in the link. CMake gives the paths to these libraries to the linker "
"by listing them on the link line explicitly. This property lists "
"in the link. This property lists "
"the dependent shared libraries of an imported library. The list "
"should be disjoint from the list of interface libraries in the "
"IMPORTED_LINK_INTERFACE_LIBRARIES property. On platforms requiring "
"dependent shared libraries to be found at link time CMake uses this "
"list to add the dependent libraries to the link command line.");
"list to add appropriate files or paths to the link command line. "
"Ignored for non-imported targets.");
cm->DefineProperty
("IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>", cmProperty::TARGET,
......
......@@ -169,6 +169,7 @@ CMAKE_CXX_SOURCES="\
cmListFileCache \
cmComputeLinkDepends \
cmComputeLinkInformation \
cmOrderRuntimeDirectories \
"
if ${cmake_system_mingw}; then
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment