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)
|
MARK_AS_ADVANCED(CMAKE_INSTALL_NAME_TOOL)
|
||||||
ENDIF(APPLE)
|
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);
|
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);
|
void GetRPath(std::vector<std::string>& runtimeDirs, bool for_install);
|
||||||
std::string GetRPathString(bool for_install);
|
std::string GetRPathString(bool for_install);
|
||||||
std::string GetChrpathString();
|
std::string GetChrpathString();
|
||||||
std::string GetChrpathTool();
|
|
||||||
std::set<cmTarget*> const& GetSharedLibrariesLinked();
|
std::set<cmTarget*> const& GetSharedLibrariesLinked();
|
||||||
|
|
||||||
std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }
|
std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }
|
||||||
|
@ -112,6 +112,10 @@ bool cmFileCommand
|
|||||||
{
|
{
|
||||||
return this->HandleInstallCommand(args);
|
return this->HandleInstallCommand(args);
|
||||||
}
|
}
|
||||||
|
else if ( subCommand == "CHRPATH" )
|
||||||
|
{
|
||||||
|
return this->HandleChrpathCommand(args);
|
||||||
|
}
|
||||||
else if ( subCommand == "RELATIVE_PATH" )
|
else if ( subCommand == "RELATIVE_PATH" )
|
||||||
{
|
{
|
||||||
return this->HandleRelativePathCommand(args);
|
return this->HandleRelativePathCommand(args);
|
||||||
@ -1326,6 +1330,34 @@ bool cmFileCommand::HandleInstallDestination(cmFileInstaller& installer,
|
|||||||
return true;
|
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)
|
bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
|
||||||
{
|
{
|
||||||
|
@ -171,6 +171,7 @@ protected:
|
|||||||
bool HandleRelativePathCommand(std::vector<std::string> const& args);
|
bool HandleRelativePathCommand(std::vector<std::string> const& args);
|
||||||
bool HandleCMakePathCommand(std::vector<std::string> const& args,
|
bool HandleCMakePathCommand(std::vector<std::string> const& args,
|
||||||
bool nativePath);
|
bool nativePath);
|
||||||
|
bool HandleChrpathCommand(std::vector<std::string> const& args);
|
||||||
|
|
||||||
// file(INSTALL ...) related functions
|
// file(INSTALL ...) related functions
|
||||||
bool HandleInstallCommand(std::vector<std::string> const& args);
|
bool HandleInstallCommand(std::vector<std::string> const& args);
|
||||||
|
@ -576,12 +576,9 @@ cmInstallTargetGenerator
|
|||||||
// Get the install RPATH from the link information.
|
// Get the install RPATH from the link information.
|
||||||
std::string newRpath = cli->GetChrpathString();
|
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
|
// Write a rule to run chrpath to set the install-tree RPATH
|
||||||
os << indent << "EXECUTE_PROCESS(COMMAND \"" << chrpathTool;
|
os << indent
|
||||||
os << "\" -r \"" << newRpath << "\" \"" << toDestDirPath << "\")\n";
|
<< "FILE(CHRPATH \"" << toDestDirPath << "\" \"" << newRpath << "\")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -2195,3 +2195,86 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
|
|||||||
}
|
}
|
||||||
return false;
|
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,
|
static bool GuessLibrarySOName(std::string const& fullPath,
|
||||||
std::string& soname);
|
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:
|
private:
|
||||||
static bool s_ForceUnixPaths;
|
static bool s_ForceUnixPaths;
|
||||||
static bool s_RunCommandHideConsole;
|
static bool s_RunCommandHideConsole;
|
||||||
|
@ -3006,8 +3006,9 @@ void cmTarget::GetLanguages(std::set<cmStdString>& languages) const
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool cmTarget::IsChrpathUsed()
|
bool cmTarget::IsChrpathUsed()
|
||||||
{
|
{
|
||||||
// Enable use of "chrpath" if it is available, the user has turned
|
#if defined(CMAKE_USE_ELF_PARSER)
|
||||||
// on the feature, and the rpath flag uses a separator.
|
// Enable if the rpath flag uses a separator and the target uses ELF
|
||||||
|
// binaries.
|
||||||
if(const char* ll = this->GetLinkerLanguage(
|
if(const char* ll = this->GetLinkerLanguage(
|
||||||
this->Makefile->GetLocalGenerator()->GetGlobalGenerator()))
|
this->Makefile->GetLocalGenerator()->GetGlobalGenerator()))
|
||||||
{
|
{
|
||||||
@ -3017,13 +3018,16 @@ bool cmTarget::IsChrpathUsed()
|
|||||||
const char* sep = this->Makefile->GetDefinition(sepVar.c_str());
|
const char* sep = this->Makefile->GetDefinition(sepVar.c_str());
|
||||||
if(sep && *sep)
|
if(sep && *sep)
|
||||||
{
|
{
|
||||||
if(this->Makefile->IsSet("CMAKE_CHRPATH") &&
|
// TODO: Add ELF check to ABI detection and get rid of
|
||||||
this->Makefile->IsOn("CMAKE_USE_CHRPATH"))
|
// CMAKE_EXECUTABLE_FORMAT.
|
||||||
|
if(const char* fmt =
|
||||||
|
this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT"))
|
||||||
{
|
{
|
||||||
return true;
|
return strcmp(fmt, "ELF") == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +335,7 @@ public:
|
|||||||
bool HaveBuildTreeRPATH();
|
bool HaveBuildTreeRPATH();
|
||||||
bool HaveInstallTreeRPATH();
|
bool HaveInstallTreeRPATH();
|
||||||
|
|
||||||
/** Return true if chrpath might work for this target */
|
/** Return true if builtin chrpath will work for this target */
|
||||||
bool IsChrpathUsed();
|
bool IsChrpathUsed();
|
||||||
|
|
||||||
std::string GetInstallNameDirForBuildTree(const char* config);
|
std::string GetInstallNameDirForBuildTree(const char* config);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user