ENH: Added RPATH methods to cmSystemTools

- RemoveRPath to remove the RPATH from a binary
  - CheckRPath to check for an existing RPATH in a binary
This commit is contained in:
Brad King 2008-04-14 15:02:34 -04:00
parent 3ff5404cca
commit b9a5dccc8d
2 changed files with 178 additions and 0 deletions

View File

@ -2463,3 +2463,173 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
return false;
#endif
}
//----------------------------------------------------------------------------
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
{
#if defined(CMAKE_USE_ELF_PARSER)
unsigned long rpathPosition = 0;
unsigned long rpathSize = 0;
unsigned long rpathEntryPosition = 0;
std::vector<char> bytes;
{
// Parse the ELF binary.
cmELF elf(file.c_str());
// Get the RPATH or RUNPATH entry from it.
cmELF::StringEntry const* se = elf.GetRPath();
if(!se)
{
se = elf.GetRunPath();
}
if(se)
{
// Store information about the entry.
rpathPosition = se->Position;
rpathSize = se->Size;
rpathEntryPosition = elf.GetDynamicEntryPosition(se->IndexInSection);
// Get the file range containing the rest of the DYNAMIC table
// after the RPATH entry.
unsigned long nextEntryPosition =
elf.GetDynamicEntryPosition(se->IndexInSection+1);
unsigned int count = elf.GetDynamicEntryCount();
if(count == 0)
{
// This should happen only for invalid ELF files where a DT_NULL
// appears before the end of the table.
if(emsg)
{
*emsg = "DYNAMIC section contains a DT_NULL before the end.";
}
return false;
}
unsigned long nullEntryPosition = elf.GetDynamicEntryPosition(count);
// Allocate and fill a buffer with zeros.
bytes.resize(nullEntryPosition - rpathEntryPosition, 0);
// Read the part of the DYNAMIC section header that will move.
// The remainder of the buffer will be left with zeros which
// represent a DT_NULL entry.
if(!elf.ReadBytes(nextEntryPosition,
nullEntryPosition - nextEntryPosition,
&bytes[0]))
{
if(emsg)
{
*emsg = "Failed to read DYNAMIC section header.";
}
return false;
}
}
else
{
// There is no RPATH or RUNPATH anyway.
return true;
}
}
// Open the file for update.
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;
}
// Write the new DYNAMIC table header.
if(!f.seekp(rpathEntryPosition))
{
if(emsg)
{
*emsg = "Error seeking to DYNAMIC table header for RPATH.";
}
return false;
}
if(!f.write(&bytes[0], bytes.size()))
{
if(emsg)
{
*emsg = "Error replacing DYNAMIC table header.";
}
return false;
}
// Fill the RPATH string with zero bytes.
if(!f.seekp(rpathPosition))
{
if(emsg)
{
*emsg = "Error seeking to RPATH position.";
}
return false;
}
for(unsigned long i=0; i < rpathSize; ++i)
{
f << '\0';
}
// Make sure everything was okay.
if(f)
{
return true;
}
else
{
if(emsg)
{
*emsg = "Error writing the empty rpath to the file.";
}
return false;
}
#else
(void)file;
(void)emsg;
return false;
#endif
}
//----------------------------------------------------------------------------
bool cmSystemTools::CheckRPath(std::string const& file,
std::string const& newRPath)
{
#if defined(CMAKE_USE_ELF_PARSER)
// Parse the ELF binary.
cmELF elf(file.c_str());
// Get the RPATH or RUNPATH entry from it.
cmELF::StringEntry const* se = elf.GetRPath();
if(!se)
{
se = elf.GetRunPath();
}
// Make sure the current rpath contains the new rpath.
if(newRPath.empty())
{
if(!se)
{
return true;
}
}
else
{
if(se &&
cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos)
{
return true;
}
}
return false;
#else
(void)file;
(void)newRPath;
return false;
#endif
}

View File

@ -393,6 +393,14 @@ public:
std::string const& newRPath,
std::string* emsg = 0);
/** Try to remove the RPATH from an ELF binary. */
static bool RemoveRPath(std::string const& file, std::string* emsg = 0);
/** Check whether the RPATH in an ELF binary contains the path
given. */
static bool CheckRPath(std::string const& file,
std::string const& newRPath);
private:
static bool s_ForceUnixPaths;
static bool s_RunCommandHideConsole;