浏览代码

cmSystemTools: Support multiple binary formats

This prepares the code to handle both the ELF and XCOFF being enabled by
trying to parse an ELF file first and if that fails falling back to XCOFF.
Alex Richardson 4 年之前
父节点
当前提交
2e1149874d
共有 1 个文件被更改,包括 139 次插入76 次删除
  1. 139 76
      Source/cmSystemTools.cxx

+ 139 - 76
Source/cmSystemTools.cxx

@@ -48,6 +48,8 @@
 
 
 #if defined(CMake_USE_ELF_PARSER)
 #if defined(CMake_USE_ELF_PARSER)
 #  include "cmELF.h"
 #  include "cmELF.h"
+#else
+class cmELF;
 #endif
 #endif
 
 
 #if defined(CMake_USE_MACH_PARSER)
 #if defined(CMake_USE_MACH_PARSER)
@@ -2491,7 +2493,6 @@ bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath,
   return false;
   return false;
 }
 }
 
 
-#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER)
 std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
 std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
                                               cm::string_view const& want)
                                               cm::string_view const& want)
 {
 {
@@ -2523,9 +2524,7 @@ std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
   // The desired rpath was not found.
   // The desired rpath was not found.
   return std::string::npos;
   return std::string::npos;
 }
 }
-#endif
 
 
-#if defined(CMake_USE_ELF_PARSER)
 namespace {
 namespace {
 struct cmSystemToolsRPathInfo
 struct cmSystemToolsRPathInfo
 {
 {
@@ -2539,11 +2538,19 @@ using EmptyCallback = std::function<bool(std::string*, const cmELF&)>;
 using AdjustCallback = std::function<bool(
 using AdjustCallback = std::function<bool(
   cm::optional<std::string>&, const std::string&, const char*, std::string*)>;
   cm::optional<std::string>&, const std::string&, const char*, std::string*)>;
 
 
-// FIXME: Dispatch if multiple formats are supported.
-bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback,
-                 const AdjustCallback& adjustCallback, std::string* emsg,
-                 bool* changed)
+cm::optional<bool> AdjustRPathELF(std::string const& file,
+                                  const EmptyCallback& emptyCallback,
+                                  const AdjustCallback& adjustCallback,
+                                  std::string* emsg, bool* changed)
 {
 {
+#if !defined(CMake_USE_ELF_PARSER)
+  (void)file;
+  (void)emptyCallback;
+  (void)adjustCallback;
+  (void)emsg;
+  (void)changed;
+  return cm::nullopt; // Cannot handle ELF files.
+#else
   if (changed) {
   if (changed) {
     *changed = false;
     *changed = false;
   }
   }
@@ -2553,6 +2560,9 @@ bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback,
   {
   {
     // Parse the ELF binary.
     // Parse the ELF binary.
     cmELF elf(file.c_str());
     cmELF elf(file.c_str());
+    if (!elf) {
+      return cm::nullopt; // Not a valid ELF file.
+    }
 
 
     // Get the RPATH and RUNPATH entries from it.
     // Get the RPATH and RUNPATH entries from it.
     int se_count = 0;
     int se_count = 0;
@@ -2668,6 +2678,7 @@ bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback,
     *changed = true;
     *changed = true;
   }
   }
   return true;
   return true;
+#endif
 }
 }
 
 
 std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback(
 std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback(
@@ -2679,21 +2690,26 @@ std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback(
       // okay.
       // okay.
       return true;
       return true;
     }
     }
+#if defined(CMake_USE_ELF_PARSER)
     if (emsg) {
     if (emsg) {
       *emsg =
       *emsg =
         cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
         cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
                  elf.GetErrorMessage());
                  elf.GetErrorMessage());
     }
     }
+#else
+    static_cast<void>(emsg);
+    static_cast<void>(elf);
+#endif
     return false;
     return false;
   };
   };
-};
+}
 }
 }
 
 
-bool cmSystemTools::ChangeRPath(std::string const& file,
-                                std::string const& oldRPath,
-                                std::string const& newRPath,
-                                bool removeEnvironmentRPath, std::string* emsg,
-                                bool* changed)
+cm::optional<bool> ChangeRPathELF(std::string const& file,
+                                  std::string const& oldRPath,
+                                  std::string const& newRPath,
+                                  bool removeEnvironmentRPath,
+                                  std::string* emsg, bool* changed)
 {
 {
   auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath](
   auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath](
                           cm::optional<std::string>& outRPath,
                           cm::optional<std::string>& outRPath,
@@ -2741,13 +2757,13 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
     return true;
     return true;
   };
   };
 
 
-  return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
-                     changed);
+  return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback,
+                        emsg, changed);
 }
 }
 
 
-bool cmSystemTools::SetRPath(std::string const& file,
-                             std::string const& newRPath, std::string* emsg,
-                             bool* changed)
+static cm::optional<bool> SetRPathELF(std::string const& file,
+                                      std::string const& newRPath,
+                                      std::string* emsg, bool* changed)
 {
 {
   auto adjustCallback = [newRPath](cm::optional<std::string>& outRPath,
   auto adjustCallback = [newRPath](cm::optional<std::string>& outRPath,
                                    const std::string& inRPath,
                                    const std::string& inRPath,
@@ -2759,22 +2775,31 @@ bool cmSystemTools::SetRPath(std::string const& file,
     return true;
     return true;
   };
   };
 
 
-  return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
-                     changed);
+  return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback,
+                        emsg, changed);
 }
 }
-#elif defined(CMake_USE_XCOFF_PARSER)
-bool cmSystemTools::ChangeRPath(std::string const& file,
-                                std::string const& oldRPath,
-                                std::string const& newRPath,
-                                bool removeEnvironmentRPath, std::string* emsg,
-                                bool* changed)
+static cm::optional<bool> ChangeRPathXCOFF(std::string const& file,
+                                           std::string const& oldRPath,
+                                           std::string const& newRPath,
+                                           bool removeEnvironmentRPath,
+                                           std::string* emsg, bool* changed)
 {
 {
   if (changed) {
   if (changed) {
     *changed = false;
     *changed = false;
   }
   }
-
+#if !defined(CMake_USE_XCOFF_PARSER)
+  (void)file;
+  (void)oldRPath;
+  (void)newRPath;
+  (void)removeEnvironmentRPath;
+  (void)emsg;
+  return cm::nullopt;
+#else
   bool chg = false;
   bool chg = false;
   cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
   cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
+  if (!xcoff) {
+    return cm::nullopt; // Not a valid XCOFF file
+  }
   if (cm::optional<cm::string_view> maybeLibPath = xcoff.GetLibPath()) {
   if (cm::optional<cm::string_view> maybeLibPath = xcoff.GetLibPath()) {
     cm::string_view libPath = *maybeLibPath;
     cm::string_view libPath = *maybeLibPath;
     // Make sure the current rpath contains the old rpath.
     // Make sure the current rpath contains the old rpath.
@@ -2830,31 +2855,47 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
     *changed = chg;
     *changed = chg;
   }
   }
   return true;
   return true;
+#endif
 }
 }
 
 
-bool cmSystemTools::SetRPath(std::string const& /*file*/,
-                             std::string const& /*newRPath*/,
-                             std::string* /*emsg*/, bool* /*changed*/)
+static cm::optional<bool> SetRPathXCOFF(std::string const& /*file*/,
+                                        std::string const& /*newRPath*/,
+                                        std::string* /*emsg*/,
+                                        bool* /*changed*/)
 {
 {
-  return false;
+  return cm::nullopt; // Not implemented.
 }
 }
-#else
-bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
-                                std::string const& /*oldRPath*/,
-                                std::string const& /*newRPath*/,
-                                bool /*removeEnvironmentRPath*/,
-                                std::string* /*emsg*/, bool* /*changed*/)
+
+bool cmSystemTools::ChangeRPath(std::string const& file,
+                                std::string const& oldRPath,
+                                std::string const& newRPath,
+                                bool removeEnvironmentRPath, std::string* emsg,
+                                bool* changed)
 {
 {
+  if (cm::optional<bool> result = ChangeRPathELF(
+        file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) {
+    return result.value();
+  }
+  if (cm::optional<bool> result = ChangeRPathXCOFF(
+        file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) {
+    return result.value();
+  }
   return false;
   return false;
 }
 }
 
 
-bool cmSystemTools::SetRPath(std::string const& /*file*/,
-                             std::string const& /*newRPath*/,
-                             std::string* /*emsg*/, bool* /*changed*/)
+bool cmSystemTools::SetRPath(std::string const& file,
+                             std::string const& newRPath, std::string* emsg,
+                             bool* changed)
 {
 {
+  if (cm::optional<bool> result = SetRPathELF(file, newRPath, emsg, changed)) {
+    return result.value();
+  }
+  if (cm::optional<bool> result =
+        SetRPathXCOFF(file, newRPath, emsg, changed)) {
+    return result.value();
+  }
   return false;
   return false;
 }
 }
-#endif
 
 
 bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
 bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
                                    const char* lhss, const char* rhss)
                                    const char* lhss, const char* rhss)
@@ -2989,11 +3030,15 @@ int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs)
   return cm_strverscmp(lhs.c_str(), rhs.c_str());
   return cm_strverscmp(lhs.c_str(), rhs.c_str());
 }
 }
 
 
-// FIXME: Dispatch if multiple formats are supported.
-#if defined(CMake_USE_ELF_PARSER)
-bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
-                                bool* removed)
+static cm::optional<bool> RemoveRPathELF(std::string const& file,
+                                         std::string* emsg, bool* removed)
 {
 {
+#if !defined(CMake_USE_ELF_PARSER)
+  (void)file;
+  (void)emsg;
+  (void)removed;
+  return cm::nullopt; // Cannot handle ELF files.
+#else
   if (removed) {
   if (removed) {
     *removed = false;
     *removed = false;
   }
   }
@@ -3005,6 +3050,9 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
   {
   {
     // Parse the ELF binary.
     // Parse the ELF binary.
     cmELF elf(file.c_str());
     cmELF elf(file.c_str());
+    if (!elf) {
+      return cm::nullopt; // Not a valid ELF file.
+    }
 
 
     // Get the RPATH and RUNPATH entries from it and sort them by index
     // Get the RPATH and RUNPATH entries from it and sort them by index
     // in the dynamic section header.
     // in the dynamic section header.
@@ -3130,16 +3178,24 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
     *removed = true;
     *removed = true;
   }
   }
   return true;
   return true;
+#endif
 }
 }
-#elif defined(CMake_USE_XCOFF_PARSER)
-bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
-                                bool* removed)
+
+static cm::optional<bool> RemoveRPathXCOFF(std::string const& file,
+                                           std::string* emsg, bool* removed)
 {
 {
   if (removed) {
   if (removed) {
     *removed = false;
     *removed = false;
   }
   }
-
+#if !defined(CMake_USE_XCOFF_PARSER)
+  (void)file;
+  (void)emsg;
+  return cm::nullopt; // Cannot handle XCOFF files.
+#else
   cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
   cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite);
+  if (!xcoff) {
+    return cm::nullopt; // Not a valid XCOFF file.
+  }
   bool rm = xcoff.RemoveLibPath();
   bool rm = xcoff.RemoveLibPath();
   if (!xcoff) {
   if (!xcoff) {
     if (emsg) {
     if (emsg) {
@@ -3152,55 +3208,62 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
     *removed = rm;
     *removed = rm;
   }
   }
   return true;
   return true;
+#endif
 }
 }
-#else
-bool cmSystemTools::RemoveRPath(std::string const& /*file*/,
-                                std::string* /*emsg*/, bool* /*removed*/)
+bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg,
+                                bool* removed)
 {
 {
+  if (cm::optional<bool> result = RemoveRPathELF(file, emsg, removed)) {
+    return result.value();
+  }
+  if (cm::optional<bool> result = RemoveRPathXCOFF(file, emsg, removed)) {
+    return result.value();
+  }
   return false;
   return false;
 }
 }
-#endif
 
 
-// FIXME: Dispatch if multiple formats are supported.
 bool cmSystemTools::CheckRPath(std::string const& file,
 bool cmSystemTools::CheckRPath(std::string const& file,
                                std::string const& newRPath)
                                std::string const& newRPath)
 {
 {
 #if defined(CMake_USE_ELF_PARSER)
 #if defined(CMake_USE_ELF_PARSER)
   // Parse the ELF binary.
   // Parse the ELF binary.
   cmELF elf(file.c_str());
   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 (elf) {
+    // Get the RPATH or RUNPATH entry from it.
+    cmELF::StringEntry const* se = elf.GetRPath();
     if (!se) {
     if (!se) {
-      return true;
+      se = elf.GetRunPath();
     }
     }
-  } else {
-    if (se &&
-        cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) {
-      return true;
+
+    // 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;
   }
   }
-  return false;
-#elif defined(CMake_USE_XCOFF_PARSER)
+#endif
+#if defined(CMake_USE_XCOFF_PARSER)
   // Parse the XCOFF binary.
   // Parse the XCOFF binary.
   cmXCOFF xcoff(file.c_str());
   cmXCOFF xcoff(file.c_str());
-  if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) {
-    if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) {
-      return true;
+  if (xcoff) {
+    if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) {
+      if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) {
+        return true;
+      }
     }
     }
+    return false;
   }
   }
-  return false;
-#else
+#endif
   (void)file;
   (void)file;
   (void)newRPath;
   (void)newRPath;
   return false;
   return false;
-#endif
 }
 }
 
 
 bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir)
 bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir)