summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/Platform/Darwin.cmake5
-rw-r--r--Source/cmComputeLinkInformation.cxx60
-rw-r--r--Source/cmExportBuildFileGenerator.cxx16
-rw-r--r--Source/cmExportBuildFileGenerator.h2
-rw-r--r--Source/cmExportFileGenerator.cxx6
-rw-r--r--Source/cmExportFileGenerator.h3
-rw-r--r--Source/cmExportInstallFileGenerator.cxx16
-rw-r--r--Source/cmExportInstallFileGenerator.h2
-rw-r--r--Source/cmExportTryCompileFileGenerator.cxx15
-rw-r--r--Source/cmExportTryCompileFileGenerator.h2
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx23
-rw-r--r--Source/cmInstallTargetGenerator.cxx76
-rw-r--r--Source/cmOrderDirectories.cxx45
-rw-r--r--Source/cmSystemTools.cxx21
-rw-r--r--Source/cmSystemTools.h4
-rw-r--r--Source/cmTarget.cxx105
-rw-r--r--Source/cmTarget.h9
-rw-r--r--Tests/CMakeLists.txt10
-rw-r--r--Tests/MacRuntimePath/A/CMakeLists.txt63
-rw-r--r--Tests/MacRuntimePath/A/framework.cpp8
-rw-r--r--Tests/MacRuntimePath/A/framework.h17
-rw-r--r--Tests/MacRuntimePath/A/shared.cpp8
-rw-r--r--Tests/MacRuntimePath/A/shared.h17
-rw-r--r--Tests/MacRuntimePath/A/test1.cpp8
-rw-r--r--Tests/MacRuntimePath/A/test2.cpp8
-rw-r--r--Tests/MacRuntimePath/A/test3.cpp8
-rw-r--r--Tests/MacRuntimePath/B/CMakeLists.txt17
-rw-r--r--Tests/MacRuntimePath/CMakeLists.txt72
-rw-r--r--Tests/MacRuntimePath/InitialCache.cmake.in13
29 files changed, 626 insertions, 33 deletions
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index 6e5d449..f0652b9 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -30,6 +30,11 @@ set(CMAKE_SHARED_MODULE_SUFFIX ".so")
set(CMAKE_MODULE_EXISTS 1)
set(CMAKE_DL_LIBS "")
+# Enable rpath support for 10.5 and greater where it is known to work.
+if("${DARWIN_MAJOR_VERSION}" GREATER 8)
+ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
+endif()
+
set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 0158508..02495c4 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -1730,6 +1730,17 @@ void
cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
cmTarget* target)
{
+ // Ignore targets on Apple where install_name is not @rpath.
+ // The dependenty library can be found with other means such as
+ // @loader_path or full paths.
+ if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ if(!target->HasMacOSXRpath(this->Config))
+ {
+ return;
+ }
+ }
+
// Libraries with unknown type must be handled using just the file
// on disk.
if(target->GetType() == cmTarget::UNKNOWN_LIBRARY)
@@ -1762,25 +1773,60 @@ void
cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath)
{
// Get the name of the library from the file name.
+ bool is_shared_library = false;
std::string file = cmSystemTools::GetFilenameName(fullPath);
- if(!this->ExtractSharedLibraryName.find(file.c_str()))
+
+ if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ // Check that @rpath is part of the install name.
+ // If it isn't, return.
+ std::string soname;
+ if(!cmSystemTools::GuessLibraryInstallName(fullPath, soname))
+ {
+ return;
+ }
+
+ if(soname.find("@rpath") == std::string::npos)
+ {
+ return;
+ }
+ }
+
+ is_shared_library = this->ExtractSharedLibraryName.find(file.c_str());
+
+ if(!is_shared_library)
{
// On some platforms (AIX) a shared library may look static.
if(this->ArchivesMayBeShared)
{
- if(!this->ExtractStaticLibraryName.find(file.c_str()))
+ if(this->ExtractStaticLibraryName.find(file.c_str()))
{
- // This is not the name of a shared library or archive.
- return;
+ // This is the name of a shared library or archive.
+ is_shared_library = true;
}
}
- else
+ }
+
+ // It could be an Apple framework
+ if(!is_shared_library)
+ {
+ if(fullPath.find(".framework") != std::string::npos)
{
- // This is not the name of a shared library.
- return;
+ cmsys::RegularExpression splitFramework;
+ splitFramework.compile("^(.*)/(.*).framework/.*/(.*)$");
+ if(splitFramework.find(fullPath) &&
+ (splitFramework.match(2) == splitFramework.match(3)))
+ {
+ is_shared_library = true;
+ }
}
}
+ if(!is_shared_library)
+ {
+ return;
+ }
+
// Include this library in the runtime path ordering.
this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
if(this->LinkWithRuntimePath)
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 245da39..39184fb 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -211,3 +211,19 @@ cmExportBuildFileGenerator
<< "consider using the APPEND option with multiple separate calls.";
this->ExportCommand->ErrorMessage = e.str();
}
+
+std::string
+cmExportBuildFileGenerator::InstallNameDir(cmTarget* target,
+ const std::string& config)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->GetMakefile();
+ if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ install_name_dir =
+ target->GetInstallNameDirForBuildTree(config.c_str());
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index 5e1be16..3ffdf8b 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -61,6 +61,8 @@ protected:
cmTarget* target,
ImportPropertyMap& properties);
+ std::string InstallNameDir(cmTarget* target, const std::string& config);
+
std::vector<cmTarget*> const* Exports;
cmExportCommand* ExportCommand;
};
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index a6ccbd5..6bef017 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -624,8 +624,12 @@ cmExportFileGenerator
std::string value;
if(target->HasSOName(config))
{
+ if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ value = this->InstallNameDir(target, config);
+ }
prop = "IMPORTED_SONAME";
- value = target->GetSOName(config);
+ value += target->GetSOName(config);
}
else
{
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index 9f958a2..ed2d93b 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -159,6 +159,9 @@ private:
std::vector<std::string> &missingTargets);
virtual void ReplaceInstallPrefix(std::string &input);
+
+ virtual std::string InstallNameDir(cmTarget* target,
+ const std::string& config) = 0;
};
#endif
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index badb8aa..dfcf472 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -491,3 +491,19 @@ cmExportInstallFileGenerator
}
cmSystemTools::Error(e.str().c_str());
}
+
+std::string
+cmExportInstallFileGenerator::InstallNameDir(cmTarget* target,
+ const std::string&)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->GetMakefile();
+ if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ install_name_dir =
+ target->GetInstallNameDirForInstallTree();
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
index 20dd57a..7c634a4 100644
--- a/Source/cmExportInstallFileGenerator.h
+++ b/Source/cmExportInstallFileGenerator.h
@@ -85,6 +85,8 @@ protected:
void ComplainAboutImportPrefix(cmInstallTargetGenerator* itgen);
+ std::string InstallNameDir(cmTarget* target, const std::string& config);
+
cmInstallExportGenerator* IEGen;
std::string ImportPrefix;
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index 75f2651..948508b 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -112,3 +112,18 @@ cmExportTryCompileFileGenerator::PopulateProperties(cmTarget* target,
}
}
}
+std::string
+cmExportTryCompileFileGenerator::InstallNameDir(cmTarget* target,
+ const std::string& config)
+{
+ std::string install_name_dir;
+
+ cmMakefile* mf = target->GetMakefile();
+ if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ install_name_dir =
+ target->GetInstallNameDirForBuildTree(config.c_str());
+ }
+
+ return install_name_dir;
+}
diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h
index ed393ab..91b4a61 100644
--- a/Source/cmExportTryCompileFileGenerator.h
+++ b/Source/cmExportTryCompileFileGenerator.h
@@ -43,6 +43,8 @@ protected:
ImportPropertyMap& properties,
std::set<cmTarget*> &emitted);
+ std::string InstallNameDir(cmTarget* target,
+ const std::string& config);
private:
std::string FindTargets(const char *prop, cmTarget *tgt,
std::set<cmTarget*> &emitted);
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 955f057..d782a06 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -2242,6 +2242,29 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
buildSettings->AddAttribute("INSTALL_PATH",
this->CreateString(install_name_dir.c_str()));
+ // Create the LD_RUNPATH_SEARCH_PATHS
+ cmComputeLinkInformation* pcli = target.GetLinkInformation(configName);
+ if(pcli)
+ {
+ std::string search_paths;
+ std::vector<std::string> runtimeDirs;
+ pcli->GetRPath(runtimeDirs, false);
+ for(std::vector<std::string>::const_iterator i = runtimeDirs.begin();
+ i != runtimeDirs.end(); ++i)
+ {
+ if(!search_paths.empty())
+ {
+ search_paths += " ";
+ }
+ search_paths += this->XCodeEscapePath((*i).c_str());
+ }
+ if(!search_paths.empty())
+ {
+ buildSettings->AddAttribute("LD_RUNPATH_SEARCH_PATHS",
+ this->CreateString(search_paths.c_str()));
+ }
+ }
+
buildSettings->AddAttribute("OTHER_LDFLAGS",
this->CreateString(extraLinkOptions.c_str()));
buildSettings->AddAttribute("OTHER_REZFLAGS",
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 9aac440..ed01210 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -606,6 +606,12 @@ cmInstallTargetGenerator
return;
}
+ // Skip if on Apple
+ if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ return;
+ }
+
// Get the link information for this target.
// It can provide the RPATH.
cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
@@ -645,30 +651,62 @@ cmInstallTargetGenerator
return;
}
- // Construct the original rpath string to be replaced.
- std::string oldRpath = cli->GetRPathString(false);
-
- // Get the install RPATH from the link information.
- std::string newRpath = cli->GetChrpathString();
-
- // Skip the rule if the paths are identical
- if(oldRpath == newRpath)
+ if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
{
- return;
- }
+ // If using install_name_tool, set up the rules to modify the rpaths.
+ std::string installNameTool =
+ this->Target->GetMakefile()->
+ GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
+
+ std::vector<std::string> oldRuntimeDirs, newRuntimeDirs;
+ cli->GetRPath(oldRuntimeDirs, false);
+ cli->GetRPath(newRuntimeDirs, true);
+
+ // Note: These are separate commands to avoid install_name_tool
+ // corruption on 10.6.
+ for(std::vector<std::string>::const_iterator i = oldRuntimeDirs.begin();
+ i != oldRuntimeDirs.end(); ++i)
+ {
+ os << indent << "execute_process(COMMAND " << installNameTool << "\n";
+ os << indent << " -delete_rpath \"" << *i << "\"\n";
+ os << indent << " \"" << toDestDirPath << "\")\n";
+ }
- // Write a rule to run chrpath to set the install-tree RPATH
- if(newRpath.empty())
- {
- os << indent << "FILE(RPATH_REMOVE\n"
- << indent << " FILE \"" << toDestDirPath << "\")\n";
+ for(std::vector<std::string>::const_iterator i = newRuntimeDirs.begin();
+ i != newRuntimeDirs.end(); ++i)
+ {
+ os << indent << "execute_process(COMMAND " << installNameTool << "\n";
+ os << indent << " -add_rpath \"" << *i << "\"\n";
+ os << indent << " \"" << toDestDirPath << "\")\n";
+ }
}
else
{
- os << indent << "FILE(RPATH_CHANGE\n"
- << indent << " FILE \"" << toDestDirPath << "\"\n"
- << indent << " OLD_RPATH \"" << oldRpath << "\"\n"
- << indent << " NEW_RPATH \"" << newRpath << "\")\n";
+ // Construct the original rpath string to be replaced.
+ std::string oldRpath = cli->GetRPathString(false);
+
+ // Get the install RPATH from the link information.
+ std::string newRpath = cli->GetChrpathString();
+
+ // Skip the rule if the paths are identical
+ if(oldRpath == newRpath)
+ {
+ return;
+ }
+
+ // Write a rule to run chrpath to set the install-tree RPATH
+ if(newRpath.empty())
+ {
+ os << indent << "FILE(RPATH_REMOVE\n"
+ << indent << " FILE \"" << toDestDirPath << "\")\n";
+ }
+ else
+ {
+ os << indent << "FILE(RPATH_CHANGE\n"
+ << indent << " FILE \"" << toDestDirPath << "\"\n"
+ << indent << " OLD_RPATH \"" << oldRpath << "\"\n"
+ << indent << " NEW_RPATH \"" << newRpath << "\")\n";
+ }
}
}
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
index 6e41768..93885b2 100644
--- a/Source/cmOrderDirectories.cxx
+++ b/Source/cmOrderDirectories.cxx
@@ -36,8 +36,25 @@ public:
OD(od), GlobalGenerator(od->GlobalGenerator)
{
this->FullPath = file;
- this->Directory = cmSystemTools::GetFilenamePath(file);
- this->FileName = cmSystemTools::GetFilenameName(file);
+
+ if(file.rfind(".framework") != std::string::npos)
+ {
+ cmsys::RegularExpression splitFramework;
+ splitFramework.compile("^(.*)/(.*).framework/.*/(.*)$");
+ if(splitFramework.find(file) &&
+ (splitFramework.match(2) == splitFramework.match(3)))
+ {
+ this->Directory = splitFramework.match(1);
+ this->FileName =
+ std::string(file.begin() + this->Directory.size() + 1, file.end());
+ }
+ }
+
+ if(this->FileName.empty())
+ {
+ this->Directory = cmSystemTools::GetFilenamePath(file);
+ this->FileName = cmSystemTools::GetFilenameName(file);
+ }
}
virtual ~cmOrderDirectoriesConstraint() {}
@@ -301,22 +318,42 @@ void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath,
// Add the runtime library at most once.
if(this->EmmittedConstraintSOName.insert(fullPath).second)
{
+ std::string soname2 = soname ? soname : "";
// Implicit link directories need special handling.
if(!this->ImplicitDirectories.empty())
{
std::string dir = cmSystemTools::GetFilenamePath(fullPath);
+
+ if(fullPath.rfind(".framework") != std::string::npos)
+ {
+ cmsys::RegularExpression splitFramework;
+ splitFramework.compile("^(.*)/(.*).framework/(.*)/(.*)$");
+ if(splitFramework.find(fullPath) &&
+ (splitFramework.match(2) == splitFramework.match(4)))
+ {
+ dir = splitFramework.match(1);
+ soname2 = splitFramework.match(2);
+ soname2 += ".framework/";
+ soname2 += splitFramework.match(3);
+ soname2 += "/";
+ soname2 += splitFramework.match(4);
+ }
+ }
+
if(this->ImplicitDirectories.find(dir) !=
this->ImplicitDirectories.end())
{
this->ImplicitDirEntries.push_back(
- new cmOrderDirectoriesConstraintSOName(this, fullPath, soname));
+ new cmOrderDirectoriesConstraintSOName(this, fullPath,
+ soname2.c_str()));
return;
}
}
// Construct the runtime information entry for this library.
this->ConstraintEntries.push_back(
- new cmOrderDirectoriesConstraintSOName(this, fullPath, soname));
+ new cmOrderDirectoriesConstraintSOName(this, fullPath,
+ soname2.c_str()));
}
else
{
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 67f3023..803d0da 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -2413,6 +2413,27 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
}
//----------------------------------------------------------------------------
+bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath,
+ std::string& soname)
+{
+ std::vector<cmStdString> cmds;
+ cmds.push_back("otool");
+ cmds.push_back("-D");
+ cmds.push_back(fullPath.c_str());
+
+ std::string output;
+ RunSingleCommand(cmds, &output, 0, 0, OUTPUT_NONE);
+
+ std::vector<std::string> strs = cmSystemTools::tokenize(output, "\n");
+ if(strs.size() == 2)
+ {
+ soname = strs[1];
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------------
#if defined(CMAKE_USE_ELF_PARSER)
std::string::size_type cmSystemToolsFindRPath(std::string const& have,
std::string const& want)
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 8355d78..f5be26b 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -439,6 +439,10 @@ public:
static bool GuessLibrarySOName(std::string const& fullPath,
std::string& soname);
+ /** Try to guess the install name of a shared library. */
+ static bool GuessLibraryInstallName(std::string const& fullPath,
+ std::string& soname);
+
/** Try to set the RPATH in an ELF binary. */
static bool ChangeRPath(std::string const& file,
std::string const& oldRPath,
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 02f7a88..4f7fa87 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -1186,6 +1186,15 @@ void cmTarget::DefineProperties(cmake *cm)
"hard-code all the settings instead of using the target properties.");
cm->DefineProperty
+ ("MACOSX_RPATH", cmProperty::TARGET,
+ "Whether to use rpaths on Mac OS X.",
+ "When this property is set to true, the directory portion of the"
+ "\"install_name\" field of shared libraries will default to \"@rpath\"."
+ "Runtime paths will also be embedded in binaries using this target."
+ "This property is initialized by the value of the variable "
+ "CMAKE_MACOSX_RPATH if it is set when a target is created.");
+
+ cm->DefineProperty
("ENABLE_EXPORTS", cmProperty::TARGET,
"Specify whether an executable exports symbols for loadable modules.",
"Normally an executable does not export any symbols because it is "
@@ -1513,6 +1522,8 @@ void cmTarget::SetMakefile(cmMakefile* mf)
this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", 0);
this->SetPropertyDefault("WIN32_EXECUTABLE", 0);
this->SetPropertyDefault("MACOSX_BUNDLE", 0);
+ this->SetPropertyDefault("MACOSX_RPATH", 0);
+
// Collect the set of configuration types.
std::vector<std::string> configNames;
@@ -3886,6 +3897,10 @@ std::string cmTarget::GetSOName(const char* config)
else
{
// Use the soname given if any.
+ if(info->SOName.find("@rpath/") == 0)
+ {
+ return info->SOName.substr(6);
+ }
return info->SOName;
}
}
@@ -3908,6 +3923,75 @@ std::string cmTarget::GetSOName(const char* config)
}
//----------------------------------------------------------------------------
+bool cmTarget::HasMacOSXRpath(const char* config)
+{
+ bool install_name_is_rpath = false;
+ bool macosx_rpath = this->GetPropertyAsBool("MACOSX_RPATH");
+
+ if(!this->IsImportedTarget)
+ {
+ const char* install_name = this->GetProperty("INSTALL_NAME_DIR");
+ bool use_install_name =
+ this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH");
+ if(install_name && use_install_name &&
+ std::string(install_name) == "@rpath")
+ {
+ install_name_is_rpath = true;
+ }
+ }
+ else
+ {
+ // Lookup the imported soname.
+ if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
+ {
+ if(!info->NoSOName && !info->SOName.empty())
+ {
+ if(info->SOName.find("@rpath/") == 0)
+ {
+ install_name_is_rpath = true;
+ }
+ }
+ else
+ {
+ std::string install_name;
+ cmSystemTools::GuessLibraryInstallName(info->Location, install_name);
+ if(install_name.find("@rpath") != std::string::npos)
+ {
+ install_name_is_rpath = true;
+ }
+ }
+ }
+ }
+
+ if(!install_name_is_rpath && !macosx_rpath)
+ {
+ return false;
+ }
+
+ if(!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG"))
+ {
+ cmOStringStream w;
+ w << "Attempting to use";
+ if(macosx_rpath)
+ {
+ w << " MACOSX_RPATH";
+ }
+ else
+ {
+ w << " @rpath";
+ }
+ w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set.";
+ w << " This could be because you are using a Mac OS X version";
+ w << " less than 10.5 or because CMake's platform configuration is";
+ w << " corrupt.";
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ cm->IssueMessage(cmake::FATAL_ERROR, w.str(), this->GetBacktrace());
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
bool cmTarget::IsImportedSharedLibWithoutSOName(const char* config)
{
if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY)
@@ -4547,7 +4631,15 @@ std::string cmTarget::GetInstallNameDirForBuildTree(const char* config)
!this->Makefile->IsOn("CMAKE_SKIP_RPATH") &&
!this->GetPropertyAsBool("SKIP_BUILD_RPATH"))
{
- std::string dir = this->GetDirectory(config);
+ std::string dir;
+ if(this->GetPropertyAsBool("MACOSX_RPATH"))
+ {
+ dir = "@rpath";
+ }
+ else
+ {
+ dir = this->GetDirectory(config);
+ }
dir += "/";
return dir;
}
@@ -4574,6 +4666,10 @@ std::string cmTarget::GetInstallNameDirForInstallTree()
dir += "/";
}
}
+ if(dir.empty() && this->GetPropertyAsBool("MACOSX_RPATH"))
+ {
+ dir = "@rpath/";
+ }
return dir;
}
else
@@ -5155,7 +5251,6 @@ void cmTarget::GetLanguages(std::set<cmStdString>& languages) const
//----------------------------------------------------------------------------
bool cmTarget::IsChrpathUsed(const char* config)
{
-#if defined(CMAKE_USE_ELF_PARSER)
// Only certain target types have an rpath.
if(!(this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY ||
@@ -5189,6 +5284,12 @@ bool cmTarget::IsChrpathUsed(const char* config)
return false;
}
+ if(this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
+ {
+ return true;
+ }
+
+#if defined(CMAKE_USE_ELF_PARSER)
// Enable if the rpath flag uses a separator and the target uses ELF
// binaries.
if(const char* ll = this->GetLinkerLanguage(config, this))
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 402379c..0bcc2a8 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -367,6 +367,9 @@ public:
/** Get the soname of the target. Allowed only for a shared library. */
std::string GetSOName(const char* config);
+ /** Whether this library has @rpath and platform supports it. */
+ bool HasMacOSXRpath(const char* config);
+
/** Test for special case of a third-party shared library that has
no soname at all. */
bool IsImportedSharedLibWithoutSOName(const char* config);
@@ -412,7 +415,13 @@ public:
/** Return true if builtin chrpath will work for this target */
bool IsChrpathUsed(const char* config);
+ /** Return the install name directory for the target in the
+ * build tree. For example: "@rpath/", "@loader_path/",
+ * or "/full/path/to/library". */
std::string GetInstallNameDirForBuildTree(const char* config);
+
+ /** Return the install name directory for the target in the
+ * install tree. For example: "@rpath/" or "@loader_path/". */
std::string GetInstallNameDirForInstallTree();
cmComputeLinkInformation* GetLinkInformation(const char* config,
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 0b221e8..fe9a5f5 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1233,6 +1233,16 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
endif()
endif()
+ if(APPLE AND "${DARWIN_MAJOR_VERSION}" GREATER 9)
+ add_test(MacRuntimePath ${CMAKE_CTEST_COMMAND}
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/MacRuntimePath"
+ "${CMake_BINARY_DIR}/Tests/MacRuntimePath"
+ ${build_generator_args}
+ --build-project MacRuntimePath
+ )
+ endif()
+
add_test(linkorder1 ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/LinkLineOrder"
diff --git a/Tests/MacRuntimePath/A/CMakeLists.txt b/Tests/MacRuntimePath/A/CMakeLists.txt
new file mode 100644
index 0000000..6e6de42
--- /dev/null
+++ b/Tests/MacRuntimePath/A/CMakeLists.txt
@@ -0,0 +1,63 @@
+cmake_minimum_required(VERSION 2.8)
+project(MacRuntimePath_A)
+
+# a shared library
+add_library(shared SHARED shared.cpp shared.h)
+set_target_properties(shared PROPERTIES MACOSX_RPATH 1)
+
+# a shared library with custom set @rpath
+add_library(shared2 SHARED shared.cpp shared.h)
+set_target_properties(shared2 PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@rpath")
+
+# a framework library
+add_library(framework SHARED framework.cpp framework.h)
+set_target_properties(framework PROPERTIES MACOSX_RPATH 1 FRAMEWORK 1)
+
+# executable to test a shared library dependency with install rpaths
+add_executable(test1 test1.cpp)
+target_link_libraries(test1 shared)
+set_target_properties(test1 PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1 INSTALL_RPATH "@loader_path/../lib")
+
+# executable to test a framework library dependency with install rpaths
+add_executable(test2 test2.cpp)
+target_link_libraries(test2 framework)
+set_target_properties(test2 PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1 INSTALL_RPATH "@loader_path/../lib")
+
+# executable to test a framework library dependency with build tree rpaths
+add_executable(test3 test3.cpp)
+target_link_libraries(test3 framework)
+
+# executable to test a framework library dependency with build tree rpaths
+add_executable(test4 test1.cpp)
+target_link_libraries(test4 shared2)
+
+set_target_properties(shared shared2 framework PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
+set_target_properties(test1 test2 test3 test4 PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+foreach(config ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER ${config} CONFIG)
+ set_target_properties(shared shared2 framework PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY_${CONFIG}
+ "${CMAKE_CURRENT_BINARY_DIR}/${config}/lib")
+ set_target_properties(test1 test2 test3 test4 PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY_${CONFIG}
+ "${CMAKE_CURRENT_BINARY_DIR}/${config}/bin")
+endforeach()
+
+foreach(test test1 test2 test3 test4)
+ add_custom_target(${test}_run ALL
+ COMMAND ${test}
+ DEPENDS ${test}
+ )
+endforeach()
+
+export(TARGETS shared shared2 framework FILE "${CMAKE_CURRENT_BINARY_DIR}/exp.cmake")
+
+install(TARGETS shared EXPORT MyExport DESTINATION lib)
+install(TARGETS shared2 EXPORT MyExport DESTINATION lib2)
+install(TARGETS framework EXPORT MyExport DESTINATION lib-fw)
+install(EXPORT MyExport DESTINATION lib FILE exp.cmake)
diff --git a/Tests/MacRuntimePath/A/framework.cpp b/Tests/MacRuntimePath/A/framework.cpp
new file mode 100644
index 0000000..abda195
--- /dev/null
+++ b/Tests/MacRuntimePath/A/framework.cpp
@@ -0,0 +1,8 @@
+
+#include "framework.h"
+#include "stdio.h"
+
+void framework()
+{
+ printf("framework\n");
+}
diff --git a/Tests/MacRuntimePath/A/framework.h b/Tests/MacRuntimePath/A/framework.h
new file mode 100644
index 0000000..bdd10f0
--- /dev/null
+++ b/Tests/MacRuntimePath/A/framework.h
@@ -0,0 +1,17 @@
+
+#ifndef framework_h
+#define framework_h
+
+#ifdef WIN32
+# ifdef framework_EXPORTS
+# define FRAMEWORK_EXPORT __declspec(dllexport)
+# else
+# define FRAMEWORK_EXPORT __declspec(dllimport)
+# endif
+#else
+# define FRAMEWORK_EXPORT
+#endif
+
+void FRAMEWORK_EXPORT framework();
+
+#endif
diff --git a/Tests/MacRuntimePath/A/shared.cpp b/Tests/MacRuntimePath/A/shared.cpp
new file mode 100644
index 0000000..e5e7dc5
--- /dev/null
+++ b/Tests/MacRuntimePath/A/shared.cpp
@@ -0,0 +1,8 @@
+
+#include "shared.h"
+#include "stdio.h"
+
+void shared()
+{
+ printf("shared\n");
+}
diff --git a/Tests/MacRuntimePath/A/shared.h b/Tests/MacRuntimePath/A/shared.h
new file mode 100644
index 0000000..3588fb8
--- /dev/null
+++ b/Tests/MacRuntimePath/A/shared.h
@@ -0,0 +1,17 @@
+
+#ifndef shared_h
+#define shared_h
+
+#ifdef WIN32
+# ifdef shared_EXPORTS
+# define SHARED_EXPORT __declspec(dllexport)
+# else
+# define SHARED_EXPORT __declspec(dllimport)
+# endif
+#else
+# define SHARED_EXPORT
+#endif
+
+void SHARED_EXPORT shared();
+
+#endif
diff --git a/Tests/MacRuntimePath/A/test1.cpp b/Tests/MacRuntimePath/A/test1.cpp
new file mode 100644
index 0000000..cb93448
--- /dev/null
+++ b/Tests/MacRuntimePath/A/test1.cpp
@@ -0,0 +1,8 @@
+
+#include "shared.h"
+
+int main(int, char**)
+{
+ shared();
+ return 0;
+}
diff --git a/Tests/MacRuntimePath/A/test2.cpp b/Tests/MacRuntimePath/A/test2.cpp
new file mode 100644
index 0000000..26bc9dd
--- /dev/null
+++ b/Tests/MacRuntimePath/A/test2.cpp
@@ -0,0 +1,8 @@
+
+#include "framework.h"
+
+int main(int, char**)
+{
+ framework();
+ return 0;
+}
diff --git a/Tests/MacRuntimePath/A/test3.cpp b/Tests/MacRuntimePath/A/test3.cpp
new file mode 100644
index 0000000..26bc9dd
--- /dev/null
+++ b/Tests/MacRuntimePath/A/test3.cpp
@@ -0,0 +1,8 @@
+
+#include "framework.h"
+
+int main(int, char**)
+{
+ framework();
+ return 0;
+}
diff --git a/Tests/MacRuntimePath/B/CMakeLists.txt b/Tests/MacRuntimePath/B/CMakeLists.txt
new file mode 100644
index 0000000..c361620
--- /dev/null
+++ b/Tests/MacRuntimePath/B/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 2.8)
+project(MacRuntimePath_B)
+
+include(${MacRuntimePath_B_BINARY_DIR}/../Root/lib/exp.cmake)
+
+add_executable(testb ${MacRuntimePath_B_SOURCE_DIR}/../A/test3.cpp)
+
+# test link with rpath enabled targets
+target_link_libraries(testb shared framework)
+
+# test link with rpath enabled library by filename
+target_link_libraries(testb $<TARGET_LINKER_FILE:shared2> framework)
+
+add_custom_target(testb_run ALL
+ COMMAND testb
+ DEPENDS testb
+ )
diff --git a/Tests/MacRuntimePath/CMakeLists.txt b/Tests/MacRuntimePath/CMakeLists.txt
new file mode 100644
index 0000000..5e5b6c4
--- /dev/null
+++ b/Tests/MacRuntimePath/CMakeLists.txt
@@ -0,0 +1,72 @@
+cmake_minimum_required (VERSION 2.8)
+project(MacRuntimePath)
+
+
+# Wipe out the install tree to make sure the exporter works.
+add_custom_command(
+ OUTPUT ${MacRuntimePath_BINARY_DIR}/CleanupProject
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${MacRuntimePath_BINARY_DIR}/Root
+ )
+add_custom_target(CleanupTarget ALL DEPENDS ${MacRuntimePath_BINARY_DIR}/CleanupProject)
+set_property(
+ SOURCE ${MacRuntimePath_BINARY_DIR}/CleanupProject
+ PROPERTY SYMBOLIC 1
+ )
+
+configure_file(${MacRuntimePath_SOURCE_DIR}/InitialCache.cmake.in
+ ${MacRuntimePath_BINARY_DIR}/InitialCache.cmake @ONLY)
+
+if(CMAKE_CONFIGURATION_TYPES)
+ set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+else()
+ if(CMAKE_BUILD_TYPE)
+ set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
+ else()
+ set(NESTED_CONFIG_TYPE)
+ endif()
+endif()
+
+# Build and install the exporter.
+add_custom_command(
+ OUTPUT ${MacRuntimePath_BINARY_DIR}/ExportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${MacRuntimePath_SOURCE_DIR}/A
+ ${MacRuntimePath_BINARY_DIR}/A
+ --build-noclean
+ --build-project MacRuntimePath_A
+ --build-target install
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-makeprogram ${CMAKE_MAKE_PROGRAM}
+ --build-options -C${MacRuntimePath_BINARY_DIR}/InitialCache.cmake
+ VERBATIM
+ )
+add_custom_target(ExportTarget ALL DEPENDS ${MacRuntimePath_BINARY_DIR}/ExportProject)
+add_dependencies(ExportTarget CleanupTarget)
+set_property(
+ SOURCE ${MacRuntimePath_BINARY_DIR}/ExportProject
+ PROPERTY SYMBOLIC 1
+ )
+
+# Build the importer.
+add_custom_command(
+ OUTPUT ${MacRuntimePath_BINARY_DIR}/ImportProject
+ COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+ --build-and-test
+ ${MacRuntimePath_SOURCE_DIR}/B
+ ${MacRuntimePath_BINARY_DIR}/B
+ --build-noclean
+ --build-project MacRuntimePath_B
+ --build-generator ${CMAKE_GENERATOR}
+ --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+ --build-makeprogram ${CMAKE_MAKE_PROGRAM}
+ --build-options -C${MacRuntimePath_BINARY_DIR}/InitialCache.cmake
+ VERBATIM
+ )
+add_custom_target(ImportTarget ALL DEPENDS ${MacRuntimePath_BINARY_DIR}/ImportProject)
+add_dependencies(ImportTarget ExportTarget)
+set_property(
+ SOURCE ${MacRuntimePath_BINARY_DIR}/ImportProject
+ PROPERTY SYMBOLIC 1
+ )
diff --git a/Tests/MacRuntimePath/InitialCache.cmake.in b/Tests/MacRuntimePath/InitialCache.cmake.in
new file mode 100644
index 0000000..be15eb3
--- /dev/null
+++ b/Tests/MacRuntimePath/InitialCache.cmake.in
@@ -0,0 +1,13 @@
+set(CMAKE_C_COMPILER "@CMAKE_C_COMPILER@" CACHE STRING "C Compiler")
+set(CMAKE_C_FLAGS "@CMAKE_C_FLAGS@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_DEBUG "@CMAKE_C_FLAGS_DEBUG@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_RELEASE "@CMAKE_C_FLAGS_RELEASE@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_MINSIZEREL "@CMAKE_C_FLAGS_MINSIZEREL@" CACHE STRING "C Flags")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "@CMAKE_C_FLAGS_RELWITHDEBINFO@" CACHE STRING "C Flags")
+set(CMAKE_CXX_COMPILER "@CMAKE_CXX_COMPILER@" CACHE STRING "C++ Compiler")
+set(CMAKE_CXX_FLAGS "@CMAKE_CXX_FLAGS@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_DEBUG "@CMAKE_CXX_FLAGS_DEBUG@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_RELEASE "@CMAKE_CXX_FLAGS_RELEASE@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "@CMAKE_CXX_FLAGS_MINSIZEREL@" CACHE STRING "C++ Flags")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "@CMAKE_CXX_FLAGS_RELWITHDEBINFO@" CACHE STRING "C++ Flags")
+set(CMAKE_INSTALL_PREFIX "@MacRuntimePath_BINARY_DIR@/Root" CACHE STRING "Installation Prefix")