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
This commit is contained in:
parent
61178a0682
commit
34c76d4304
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue