From 3ae731fab7a3b992c321226262076a2622f64c11 Mon Sep 17 00:00:00 2001 From: Alexander Neundorf Date: Tue, 18 Dec 2007 17:50:27 -0500 Subject: ENH: add support for chrpath, so the RPATH in ELF files can be changed when installing without having to link the target again -> can save a lot of time chrpath is handled very similar to install_name_tool on the mac. If the RPATH in the build tree file is to short, it is padded using the separator character. This is currently disabled by default, it can be enabled using the option CMAKE_USE_CHRPATH. There are additional checks whether it is safe to enable it. I will rework them and use FILE(READ) instead to detect whether the binaries are actually ELF files. chrpath is available here http://www.tux.org/pub/X-Windows/ftp.hungry.com/chrpath/ or kde svn (since a few days): http://websvn.kde.org/trunk/kdesupport/chrpath/ Alex --- Modules/CMakeFindBinUtils.cmake | 10 +++++++ Source/cmInstallTargetGenerator.cxx | 55 +++++++++++++++++++++++++++++++++++++ Source/cmInstallTargetGenerator.h | 3 ++ Source/cmLocalGenerator.cxx | 29 +++++++++++++++++-- Source/cmLocalGenerator.h | 11 +++++--- Source/cmTarget.cxx | 45 ++++++++++++++++++++++++++++++ Source/cmTarget.h | 3 ++ 7 files changed, 150 insertions(+), 6 deletions(-) diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake index 2cb7696..43f76f7 100644 --- a/Modules/CMakeFindBinUtils.cmake +++ b/Modules/CMakeFindBinUtils.cmake @@ -75,3 +75,13 @@ IF(APPLE) MARK_AS_ADVANCED(CMAKE_INSTALL_NAME_TOOL) ENDIF(APPLE) +IF(UNIX AND NOT APPLE AND NOT WIN32) + # on ELF platforms there might be chrpath, which works similar to install_name_tool + OPTION(CMAKE_USE_CHRPATH "Enable this to use chrpath if available" OFF) + + FIND_PROGRAM(CMAKE_CHRPATH chrpath PATHS ${_CMAKE_TOOLCHAIN_LOCATION} NO_DEFAULT_PATH) + FIND_PROGRAM(CMAKE_CHRPATH chrpath) + + MARK_AS_ADVANCED(CMAKE_CHRPATH) +ENDIF(UNIX AND NOT APPLE AND NOT WIN32) + diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index abe9348..9998d0d 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -305,6 +305,7 @@ cmInstallTargetGenerator os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n"; this->AddInstallNamePatchRule(os, indent.Next(), config, toDestDirPath); + this->AddChrpathPatchRule(os, indent.Next(), config, toDestDirPath); this->AddRanlibRule(os, indent.Next(), type, toDestDirPath); this->AddStripRule(os, indent.Next(), type, toDestDirPath); os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n"; @@ -506,6 +507,60 @@ cmInstallTargetGenerator //---------------------------------------------------------------------------- void +cmInstallTargetGenerator +::AddChrpathPatchRule(std::ostream& os, Indent const& indent, + const char* config, std::string const& toDestDirPath) +{ + if(this->ImportLibrary || + !(this->Target->GetType() == cmTarget::SHARED_LIBRARY || + this->Target->GetType() == cmTarget::MODULE_LIBRARY || + this->Target->GetType() == cmTarget::EXECUTABLE)) + { + return; + } + + if((this->Target->GetMakefile()->IsOn("CMAKE_USE_CHRPATH")==false) + || (this->Target->IsChrpathAvailable()==false)) + { + return; + } + + // Fix the RPATH in installed ELF binaries using chrpath. + std::string chrpathTool = + this->Target->GetMakefile()->GetSafeDefinition("CMAKE_CHRPATH"); + + std::string installRpath; + std::string dummy; + this->Target->GetMakefile()->GetLocalGenerator()->GetLinkerArgs( + installRpath, dummy, *this->Target, true, 0); + + const char* linkLanguage = this->Target->GetLinkerLanguage(this->Target-> + GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()); + if (linkLanguage==0) + { + return; + } + + std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; + runTimeFlagVar += linkLanguage; + runTimeFlagVar += "_FLAG"; + + std::string runtimeFlag = + this->Target->GetMakefile()->GetSafeDefinition(runTimeFlagVar.c_str()); + + const char* newRpath=installRpath.c_str(); + if (strstr(installRpath.c_str(), runtimeFlag.c_str())==installRpath.c_str()) + { + newRpath = installRpath.c_str()+strlen(runtimeFlag.c_str()); + } + + // Write a rule to run chrpath to set the install-tree RPATH + os << indent << "EXECUTE_PROCESS(COMMAND \"" << chrpathTool; + os << "\" -r \"" << newRpath << "\" \"" << toDestDirPath << "\")\n"; +} + +//---------------------------------------------------------------------------- +void cmInstallTargetGenerator::AddStripRule(std::ostream& os, Indent const& indent, cmTarget::TargetType type, diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index d03ea3d..3fdd5bf 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -54,6 +54,9 @@ protected: void AddInstallNamePatchRule(std::ostream& os, Indent const& indent, const char* config, const std::string& toDestDirPath); + void AddChrpathPatchRule(std::ostream& os, Indent const& indent, + const char* config, std::string const& toDestDirPath); + void AddStripRule(std::ostream& os, Indent const& indent, cmTarget::TargetType type, const std::string& toDestDirPath); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 6c081b9..bf91751 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1479,7 +1479,8 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, bool cmLocalGenerator::GetLinkerArgs(std::string& rpath, std::string& linkLibs, cmTarget& tgt, - bool relink) + bool relink, + int minRpathSize) { rpath = ""; // collect all the flags needed for linking libraries @@ -1656,6 +1657,18 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath, } } } + + if (rpath.size()GetLinkerArgs(rpath, linkLibs, tgt, relink)) + int minBuildRpathSize = 0; + + if ((relink==false) + && this->Makefile->IsOn("CMAKE_USE_CHRPATH") + && (tgt.IsChrpathAvailable())) + { + std::string installRpath; + std::string dummy; + this->GetLinkerArgs(installRpath, dummy, tgt, true, 0); + minBuildRpathSize=installRpath.size(); + } + + if (!this->GetLinkerArgs(rpath, linkLibs, tgt, relink, minBuildRpathSize)) { return; } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 9f24f3f..1015251 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -242,6 +242,13 @@ public: */ virtual std::string GetTargetDirectory(cmTarget const& target) const; + ///! Determine the arguments for the linker call, used also by + /// cmInstallTargetGenerator + bool GetLinkerArgs(std::string& rpath, std::string& linkLibs, + cmTarget& tgt, bool relink, int minRpathSize); + + bool IsChrpathAvailable(const cmTarget& target); + protected: /** Construct a comment for a custom command. */ @@ -258,10 +265,6 @@ protected: ///! put all the libraries for a target on into the given stream virtual void OutputLinkLibraries(std::ostream&, cmTarget&, bool relink); - ///! Determine the arguments for the linker call - bool GetLinkerArgs(std::string& rpath, std::string& linkLibs, - cmTarget& tgt, bool relink); - // Expand rule variables in CMake of the type found in language rules void ExpandRuleVariables(std::string& string, const RuleVariables& replaceValues); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 2f4bb67..daca41f 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -2242,6 +2242,12 @@ bool cmTarget::NeedRelinkBeforeInstall() return false; } + if(this->Makefile->IsOn("CMAKE_USE_CHRPATH") + && (this->IsChrpathAvailable())) + { + return false; + } + // If skipping all rpaths completely then no relinking is needed. if(this->Makefile->IsOn("CMAKE_SKIP_RPATH")) { @@ -2518,3 +2524,42 @@ void cmTarget::GetLanguages(std::set& languages) const } } } + +bool cmTarget::IsChrpathAvailable() +{ + //only return true if the flag is "-Wl,rpath," amd the separator is not empty + if (this->Makefile->IsSet("CMAKE_CHRPATH")==false) + { + return false; + } + + const char* linkLanguage = this->GetLinkerLanguage(this->Makefile-> + GetLocalGenerator()->GetGlobalGenerator()); + if (linkLanguage==0) + { + return false; + } + + std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; + runTimeFlagVar += linkLanguage; + runTimeFlagVar += "_FLAG"; + std::string runTimeFlagSepVar = runTimeFlagVar + "_SEP"; + + std::string runtimeSep = + this->Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str()); + + if (runtimeSep.size()<=0) + { + return 0; + } + + std::string runtimeFlag = + this->Makefile->GetSafeDefinition(runTimeFlagVar.c_str()); + + if (runtimeFlag!="-Wl,-rpath,") + { + return false; + } + + return true; +} diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 44e0a05..879693a 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -277,6 +277,9 @@ public: bool HaveBuildTreeRPATH(); bool HaveInstallTreeRPATH(); + + /// return true if chrpath might work for this target + bool IsChrpathAvailable(); std::string GetInstallNameDirForBuildTree(const char* config); std::string GetInstallNameDirForInstallTree(const char* config); -- cgit v0.12