summaryrefslogtreecommitdiffstats
path: root/Source/cmSystemTools.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r--Source/cmSystemTools.cxx189
1 files changed, 119 insertions, 70 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index f4ce41c..ba85034 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -2329,6 +2329,16 @@ std::string::size_type cmSystemToolsFindRPath(std::string const& have,
}
#endif
+#if defined(CMAKE_USE_ELF_PARSER)
+struct cmSystemToolsRPathInfo
+{
+ unsigned long Position;
+ unsigned long Size;
+ std::string Name;
+ std::string Value;
+};
+#endif
+
//----------------------------------------------------------------------------
bool cmSystemTools::ChangeRPath(std::string const& file,
std::string const& oldRPath,
@@ -2341,37 +2351,71 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
{
*changed = false;
}
- unsigned long rpathPosition = 0;
- unsigned long rpathSize = 0;
- std::string rpathPrefix;
- std::string rpathSuffix;
+ int rp_count = 0;
+ cmSystemToolsRPathInfo rp[2];
{
// 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)
+ // Get the RPATH and RUNPATH entries from it.
+ int se_count = 0;
+ cmELF::StringEntry const* se[2] = {0, 0};
+ const char* se_name[2] = {0, 0};
+ if(cmELF::StringEntry const* se_rpath = elf.GetRPath())
{
- se = elf.GetRunPath();
+ se[se_count] = se_rpath;
+ se_name[se_count] = "RPATH";
+ ++se_count;
+ }
+ if(cmELF::StringEntry const* se_runpath = elf.GetRunPath())
+ {
+ se[se_count] = se_runpath;
+ se_name[se_count] = "RUNPATH";
+ ++se_count;
+ }
+ if(se_count == 0)
+ {
+ if(newRPath.empty())
+ {
+ // The new rpath is empty and there is no rpath anyway so it is
+ // okay.
+ return true;
+ }
+ else
+ {
+ if(emsg)
+ {
+ *emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; ";
+ *emsg += elf.GetErrorMessage();
+ }
+ return false;
+ }
}
- if(se)
+ for(int i=0; i < se_count; ++i)
{
+ // If both RPATH and RUNPATH refer to the same string literal it
+ // needs to be changed only once.
+ if(rp_count && rp[0].Position == se[i]->Position)
+ {
+ continue;
+ }
+
// Make sure the current rpath contains the old rpath.
- std::string::size_type pos = cmSystemToolsFindRPath(se->Value, oldRPath);
+ std::string::size_type pos =
+ cmSystemToolsFindRPath(se[i]->Value, oldRPath);
if(pos == std::string::npos)
{
// If it contains the new rpath instead then it is okay.
- if(cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos)
+ if(cmSystemToolsFindRPath(se[i]->Value, newRPath) != std::string::npos)
{
- return true;
+ continue;
}
if(emsg)
{
cmOStringStream e;
- e << "The current RPATH is:\n"
- << " " << se->Value << "\n"
+ e << "The current " << se_name[i] << " is:\n"
+ << " " << se[i]->Value << "\n"
<< "which does not contain:\n"
<< " " << oldRPath << "\n"
<< "as was expected.";
@@ -2380,47 +2424,43 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
return false;
}
- // Store information about the entry.
- rpathPosition = se->Position;
- rpathSize = se->Size;
+ // Store information about the entry in the file.
+ rp[rp_count].Position = se[i]->Position;
+ rp[rp_count].Size = se[i]->Size;
+ rp[rp_count].Name = se_name[i];
- // Store the part of the path we must preserve.
- rpathPrefix = se->Value.substr(0, pos);
- rpathSuffix = se->Value.substr(pos+oldRPath.length(), oldRPath.npos);
- }
- else if(newRPath.empty())
- {
- // The new rpath is empty and there is no rpath anyway so it is
- // okay.
- return true;
- }
- else
- {
- if(emsg)
+ // Construct the new value which preserves the part of the path
+ // not being changed.
+ rp[rp_count].Value = se[i]->Value.substr(0, pos);
+ rp[rp_count].Value += newRPath;
+ rp[rp_count].Value += se[i]->Value.substr(pos+oldRPath.length(),
+ oldRPath.npos);
+
+ // Make sure there is enough room to store the new rpath and at
+ // least one null terminator.
+ if(rp[rp_count].Size < rp[rp_count].Value.length()+1)
{
- *emsg = "No valid ELF RPATH entry exists in the file; ";
- *emsg += elf.GetErrorMessage();
+ if(emsg)
+ {
+ *emsg = "The replacement path is too long for the ";
+ *emsg += se_name[i];
+ *emsg += " entry.";
+ }
+ return false;
}
- return false;
+
+ // This entry is ready for update.
+ ++rp_count;
}
}
- // Compute the full new rpath.
- std::string rpath = rpathPrefix;
- rpath += newRPath;
- rpath += rpathSuffix;
- // Make sure there is enough room to store the new rpath and at
- // least one null terminator.
- if(rpathSize < rpath.length()+1)
+ // If no runtime path needs to be changed, we are done.
+ if(rp_count == 0)
{
- if(emsg)
- {
- *emsg = "The replacement RPATH is too long.";
- }
- return false;
+ return true;
}
- // Open the file for update and seek to the RPATH position.
+ // Open the file for update.
std::ofstream f(file.c_str(),
std::ios::in | std::ios::out | std::ios::binary);
if(!f)
@@ -2431,40 +2471,49 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
}
return false;
}
- if(!f.seekp(rpathPosition))
+
+ // Store the new RPATH and RUNPATH strings.
+ for(int i=0; i < rp_count; ++i)
{
- if(emsg)
+ // Seek to the RPATH position.
+ if(!f.seekp(rp[i].Position))
{
- *emsg = "Error seeking to RPATH position.";
+ if(emsg)
+ {
+ *emsg = "Error seeking to ";
+ *emsg += rp[i].Name;
+ *emsg += " position.";
+ }
+ return false;
}
- return false;
- }
- // Write the new rpath. Follow it with enough null terminators to
- // fill the string table entry.
- f << rpath;
- for(unsigned long i=rpath.length(); i < rpathSize; ++i)
- {
- f << '\0';
- }
+ // Write the new rpath. Follow it with enough null terminators to
+ // fill the string table entry.
+ f << rp[i].Value;
+ for(unsigned long j=rp[i].Value.length(); j < rp[i].Size; ++j)
+ {
+ f << '\0';
+ }
- // Make sure everything was okay.
- if(f)
- {
- if(changed)
+ // Make sure it wrote correctly.
+ if(!f)
{
- *changed = true;
+ if(emsg)
+ {
+ *emsg = "Error writing the new ";
+ *emsg += rp[i].Name;
+ *emsg += " string to the file.";
+ }
+ return false;
}
- return true;
}
- else
+
+ // Everything was updated successfully.
+ if(changed)
{
- if(emsg)
- {
- *emsg = "Error writing the new rpath to the file.";
- }
- return false;
+ *changed = true;
}
+ return true;
#else
(void)file;
(void)oldRPath;