Commit 3ae731fa authored by Alexander Neundorf's avatar Alexander Neundorf
Browse files

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
parent f5f397de
......@@ -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)
......@@ -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";
......@@ -504,6 +505,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,
......
......@@ -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);
......
......@@ -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()<minRpathSize)
{
if (rpath.size()==0)
{
rpath += runtimeFlag;
}
while (rpath.size() < minRpathSize)
{
rpath += runtimeSep;
}
}
return true;
}
......@@ -1670,7 +1683,19 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
{
std::string rpath;
std::string linkLibs;
if (!this->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;
}
......
......@@ -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);
......
......@@ -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<cmStdString>& 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;
}
......@@ -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);
......
Supports Markdown
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