Commit 34c76d43 authored by Brad King's avatar Brad King
Browse files

ENH: Use builtin chrpath instead of relinking ELF targets

  - Add cmSystemTools::ChangeRPath method
  - Add undocumented file(CHRPATH) command
  - When installing use file(CHRPATH) to change the rpath
    instead of relinking
  - Remove CMAKE_CHRPATH lookup from CMakeFindBinUtils
  - Remove CMAKE_USE_CHRPATH option since this should
    always work
parent 61178a06
......@@ -74,16 +74,3 @@ IF(APPLE)
MARK_AS_ADVANCED(CMAKE_INSTALL_NAME_TOOL)
ENDIF(APPLE)
# if we are on an ELF system, search for chrpath
# according to the binutils mailing list chrpath has problems when cross compiling
# i.e. if the target has different endianness than the host
IF("${CMAKE_EXECUTABLE_FORMAT}" STREQUAL "ELF" AND NOT CMAKE_CROSSCOMPILING)
# 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 CMAKE_USE_CHRPATH)
ENDIF("${CMAKE_EXECUTABLE_FORMAT}" STREQUAL "ELF" AND NOT CMAKE_CROSSCOMPILING)
......@@ -1476,9 +1476,3 @@ std::string cmComputeLinkInformation::GetChrpathString()
return this->GetRPathString(true);
}
//----------------------------------------------------------------------------
std::string cmComputeLinkInformation::GetChrpathTool()
{
return this->Makefile->GetSafeDefinition("CMAKE_CHRPATH");
}
......@@ -58,7 +58,6 @@ public:
void GetRPath(std::vector<std::string>& runtimeDirs, bool for_install);
std::string GetRPathString(bool for_install);
std::string GetChrpathString();
std::string GetChrpathTool();
std::set<cmTarget*> const& GetSharedLibrariesLinked();
std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }
......
......@@ -112,6 +112,10 @@ bool cmFileCommand
{
return this->HandleInstallCommand(args);
}
else if ( subCommand == "CHRPATH" )
{
return this->HandleChrpathCommand(args);
}
else if ( subCommand == "RELATIVE_PATH" )
{
return this->HandleRelativePathCommand(args);
......@@ -1326,6 +1330,34 @@ bool cmFileCommand::HandleInstallDestination(cmFileInstaller& installer,
return true;
}
//----------------------------------------------------------------------------
bool cmFileCommand::HandleChrpathCommand(std::vector<std::string> const& args)
{
if(args.size() != 3)
{
this->SetError("CHRPATH must be given a file and a new rpath.");
return false;
}
if(!cmSystemTools::FileExists(args[1].c_str(), true))
{
this->SetError("CHRPATH given file that does not exist.");
return false;
}
std::string emsg;
if(cmSystemTools::ChangeRPath(args[1], args[2], &emsg))
{
return true;
}
else
{
cmOStringStream e;
e << "CHRPATH could not write new RPATH to the file: "
<< emsg;
this->SetError(e.str().c_str());
return false;
}
}
//----------------------------------------------------------------------------
bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
{
......
......@@ -171,6 +171,7 @@ protected:
bool HandleRelativePathCommand(std::vector<std::string> const& args);
bool HandleCMakePathCommand(std::vector<std::string> const& args,
bool nativePath);
bool HandleChrpathCommand(std::vector<std::string> const& args);
// file(INSTALL ...) related functions
bool HandleInstallCommand(std::vector<std::string> const& args);
......
......@@ -576,12 +576,9 @@ cmInstallTargetGenerator
// Get the install RPATH from the link information.
std::string newRpath = cli->GetChrpathString();
// Fix the RPATH in installed ELF binaries using chrpath.
std::string chrpathTool = cli->GetChrpathTool();
// Write a rule to run chrpath to set the install-tree RPATH
os << indent << "EXECUTE_PROCESS(COMMAND \"" << chrpathTool;
os << "\" -r \"" << newRpath << "\" \"" << toDestDirPath << "\")\n";
os << indent
<< "FILE(CHRPATH \"" << toDestDirPath << "\" \"" << newRpath << "\")\n";
}
//----------------------------------------------------------------------------
......
......@@ -2195,3 +2195,86 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
}
return false;
}
//----------------------------------------------------------------------------
bool cmSystemTools::ChangeRPath(std::string const& file,
std::string const& newRPath,
std::string* emsg)
{
#if defined(CMAKE_USE_ELF_PARSER)
unsigned long rpathPosition = 0;
unsigned long rpathSize = 0;
{
cmELF elf(file.c_str());
if(cmELF::StringEntry const* se = elf.GetRPath())
{
rpathPosition = se->Position;
rpathSize = se->Size;
}
else
{
if(emsg)
{
*emsg = "No valid ELF RPATH entry exists in the file.";
}
return false;
}
}
// Make sure there is enough room to store the new rpath and at
// least one null terminator.
if(rpathSize < newRPath.length()+1)
{
if(emsg)
{
*emsg = "The replacement RPATH is too long.";
}
return false;
}
// Open the file for update and seek to the RPATH position.
std::ofstream f(file.c_str(),
std::ios::in | std::ios::out | std::ios::binary);
if(!f)
{
if(emsg)
{
*emsg = "Error opening file for update.";
}
return false;
}
if(!f.seekp(rpathPosition))
{
if(emsg)
{
*emsg = "Error seeking to RPATH position.";
}
return false;
}
// Write the new rpath. Follow it with enough null terminators to
// fill the string table entry.
f << newRPath;
for(unsigned long i=newRPath.length(); i < rpathSize; ++i)
{
f << '\0';
}
// Make sure everything was okay.
if(f)
{
return true;
}
else
{
if(emsg)
{
*emsg = "Error writing the new rpath to the file.";
}
return false;
}
#else
(void)file;
(void)newRPath;
return false;
#endif
}
......@@ -381,6 +381,11 @@ public:
static bool GuessLibrarySOName(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& newRPath,
std::string* emsg = 0);
private:
static bool s_ForceUnixPaths;
static bool s_RunCommandHideConsole;
......
......@@ -3006,8 +3006,9 @@ void cmTarget::GetLanguages(std::set<cmStdString>& languages) const
//----------------------------------------------------------------------------
bool cmTarget::IsChrpathUsed()
{
// Enable use of "chrpath" if it is available, the user has turned
// on the feature, and the rpath flag uses a separator.
#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(
this->Makefile->GetLocalGenerator()->GetGlobalGenerator()))
{
......@@ -3017,13 +3018,16 @@ bool cmTarget::IsChrpathUsed()
const char* sep = this->Makefile->GetDefinition(sepVar.c_str());
if(sep && *sep)
{
if(this->Makefile->IsSet("CMAKE_CHRPATH") &&
this->Makefile->IsOn("CMAKE_USE_CHRPATH"))
// TODO: Add ELF check to ABI detection and get rid of
// CMAKE_EXECUTABLE_FORMAT.
if(const char* fmt =
this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT"))
{
return true;
return strcmp(fmt, "ELF") == 0;
}
}
}
#endif
return false;
}
......
......@@ -335,7 +335,7 @@ public:
bool HaveBuildTreeRPATH();
bool HaveInstallTreeRPATH();
/** Return true if chrpath might work for this target */
/** Return true if builtin chrpath will work for this target */
bool IsChrpathUsed();
std::string GetInstallNameDirForBuildTree(const char* config);
......
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