Browse Source

install: Do not remove compiler-defined RPATH entries

Some compilers may add their own RPATH entries when invoking the linker.
For example, a GCC installation may contain the following definition in
the specs file:

  *link_libgcc:
  %D -rpath <<some specific rpath in which libstdc++.so can be found>>

In this case binaries may contain RPATH entries that CMake did not add.
When we update the RPATH on installation we must preserve these entries
even if CMake thinks the INSTALL_RPATH value should be empty.

Fix this by always using file(RPATH_CHANGE) and teach it to behave as
file(RPATH_REMOVE) if the actual RPATH in the file is empty after
replacing the build-tree RPATH with the install-tree RPATH.  This will
preserve any compiler-added RPATH value instead of removing it.
Lior Goldberg 9 years ago
parent
commit
3ec9226779
2 changed files with 30 additions and 13 deletions
  1. 4 12
      Source/cmInstallTargetGenerator.cxx
  2. 26 1
      Source/cmSystemTools.cxx

+ 4 - 12
Source/cmInstallTargetGenerator.cxx

@@ -791,18 +791,10 @@ cmInstallTargetGenerator
       }
 
     // Write a rule to run chrpath to set the install-tree RPATH
-    if(newRpath.empty())
-      {
-      os << indent << "file(RPATH_REMOVE\n"
-         << indent << "     FILE \"" << toDestDirPath << "\")\n";
-      }
-    else
-      {
-      os << indent << "file(RPATH_CHANGE\n"
-         << indent << "     FILE \"" << toDestDirPath << "\"\n"
-         << indent << "     OLD_RPATH \"" << oldRpath << "\"\n"
-         << indent << "     NEW_RPATH \"" << newRpath << "\")\n";
-      }
+    os << indent << "file(RPATH_CHANGE\n"
+       << indent << "     FILE \"" << toDestDirPath << "\"\n"
+       << indent << "     OLD_RPATH \"" << oldRpath << "\"\n"
+       << indent << "     NEW_RPATH \"" << newRpath << "\")\n";
     }
 }
 

+ 26 - 1
Source/cmSystemTools.cxx

@@ -2565,6 +2565,7 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
     *changed = false;
     }
   int rp_count = 0;
+  bool remove_rpath = true;
   cmSystemToolsRPathInfo rp[2];
   {
   // Parse the ELF binary.
@@ -2622,6 +2623,7 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
       // If it contains the new rpath instead then it is okay.
       if(cmSystemToolsFindRPath(se[i]->Value, newRPath) != std::string::npos)
         {
+        remove_rpath = false;
         continue;
         }
       if(emsg)
@@ -2642,13 +2644,30 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
     rp[rp_count].Size = se[i]->Size;
     rp[rp_count].Name = se_name[i];
 
+    std::string::size_type prefix_len = pos;
+
+    // If oldRPath was at the end of the file's RPath, and newRPath is empty,
+    // we should remove the unnecessary ':' at the end.
+    if (newRPath.empty() &&
+        pos > 0 &&
+        se[i]->Value[pos - 1] == ':' &&
+        pos + oldRPath.length() == se[i]->Value.length())
+      {
+      prefix_len--;
+      }
+
     // 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 = se[i]->Value.substr(0, prefix_len);
     rp[rp_count].Value += newRPath;
     rp[rp_count].Value += se[i]->Value.substr(pos+oldRPath.length(),
                                               oldRPath.npos);
 
+    if (!rp[rp_count].Value.empty())
+      {
+      remove_rpath = false;
+      }
+
     // 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)
@@ -2673,6 +2692,12 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
     return true;
     }
 
+  // If the resulting rpath is empty, just remove the entire entry instead.
+  if (remove_rpath)
+    {
+    return cmSystemTools::RemoveRPath(file, emsg, changed);
+    }
+
   {
   // Open the file for update.
   cmsys::ofstream f(file.c_str(),