|
|
@@ -14,6 +14,7 @@
|
|
|
|
|
|
#include "cmSystemTools.h"
|
|
|
|
|
|
+#include <cm/optional>
|
|
|
#include <cmext/algorithm>
|
|
|
|
|
|
#include <cm3p/uv.h>
|
|
|
@@ -65,6 +66,7 @@
|
|
|
#include <cstdlib>
|
|
|
#include <cstring>
|
|
|
#include <ctime>
|
|
|
+#include <functional>
|
|
|
#include <iostream>
|
|
|
#include <sstream>
|
|
|
#include <utility>
|
|
|
@@ -2524,6 +2526,7 @@ std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
|
|
|
#endif
|
|
|
|
|
|
#if defined(CMake_USE_ELF_PARSER)
|
|
|
+namespace {
|
|
|
struct cmSystemToolsRPathInfo
|
|
|
{
|
|
|
unsigned long Position;
|
|
|
@@ -2531,15 +2534,15 @@ struct cmSystemToolsRPathInfo
|
|
|
std::string Name;
|
|
|
std::string Value;
|
|
|
};
|
|
|
-#endif
|
|
|
+
|
|
|
+using EmptyCallback = std::function<bool(std::string*, const cmELF&)>;
|
|
|
+using AdjustCallback = std::function<bool(
|
|
|
+ cm::optional<std::string>&, const std::string&, const char*, std::string*)>;
|
|
|
|
|
|
// FIXME: Dispatch if multiple formats are supported.
|
|
|
-#if defined(CMake_USE_ELF_PARSER)
|
|
|
-bool cmSystemTools::ChangeRPath(std::string const& file,
|
|
|
- std::string const& oldRPath,
|
|
|
- std::string const& newRPath,
|
|
|
- bool removeEnvironmentRPath, std::string* emsg,
|
|
|
- bool* changed)
|
|
|
+bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback,
|
|
|
+ const AdjustCallback& adjustCallback, std::string* emsg,
|
|
|
+ bool* changed)
|
|
|
{
|
|
|
if (changed) {
|
|
|
*changed = false;
|
|
|
@@ -2566,17 +2569,7 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
|
|
++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;
|
|
|
- }
|
|
|
- if (emsg) {
|
|
|
- *emsg =
|
|
|
- cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
|
|
|
- elf.GetErrorMessage());
|
|
|
- }
|
|
|
- return false;
|
|
|
+ return emptyCallback(emsg, elf);
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < se_count; ++i) {
|
|
|
@@ -2586,68 +2579,38 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- // Make sure the current rpath contains the old rpath.
|
|
|
- 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[i]->Value, newRPath) !=
|
|
|
- std::string::npos) {
|
|
|
- remove_rpath = false;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (emsg) {
|
|
|
- std::ostringstream e;
|
|
|
- /* clang-format off */
|
|
|
- e << "The current " << se_name[i] << " is:\n"
|
|
|
- << " " << se[i]->Value << "\n"
|
|
|
- << "which does not contain:\n"
|
|
|
- << " " << oldRPath << "\n"
|
|
|
- << "as was expected.";
|
|
|
- /* clang-format on */
|
|
|
- *emsg = e.str();
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
// 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];
|
|
|
|
|
|
- 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.
|
|
|
- if (!removeEnvironmentRPath) {
|
|
|
- rp[rp_count].Value = se[i]->Value.substr(0, prefix_len);
|
|
|
+ // Adjust the rpath.
|
|
|
+ cm::optional<std::string> outRPath;
|
|
|
+ if (!adjustCallback(outRPath, se[i]->Value, se_name[i], emsg)) {
|
|
|
+ return false;
|
|
|
}
|
|
|
- rp[rp_count].Value += newRPath;
|
|
|
- rp[rp_count].Value += se[i]->Value.substr(pos + oldRPath.length());
|
|
|
|
|
|
- if (!rp[rp_count].Value.empty()) {
|
|
|
- remove_rpath = false;
|
|
|
- }
|
|
|
+ if (outRPath) {
|
|
|
+ if (!outRPath->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) {
|
|
|
- if (emsg) {
|
|
|
- *emsg = cmStrCat("The replacement path is too long for the ",
|
|
|
- se_name[i], " entry.");
|
|
|
+ // Make sure there is enough room to store the new rpath and at
|
|
|
+ // least one null terminator.
|
|
|
+ if (rp[rp_count].Size < outRPath->length() + 1) {
|
|
|
+ if (emsg) {
|
|
|
+ *emsg = cmStrCat("The replacement path is too long for the ",
|
|
|
+ se_name[i], " entry.");
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
- return false;
|
|
|
- }
|
|
|
|
|
|
- // This entry is ready for update.
|
|
|
- ++rp_count;
|
|
|
+ // This entry is ready for update.
|
|
|
+ rp[rp_count].Value = std::move(*outRPath);
|
|
|
+ ++rp_count;
|
|
|
+ } else {
|
|
|
+ remove_rpath = false;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -2706,6 +2669,81 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
+std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback(
|
|
|
+ const std::string& newRPath)
|
|
|
+{
|
|
|
+ return [newRPath](std::string* emsg, const cmELF& elf) -> bool {
|
|
|
+ if (newRPath.empty()) {
|
|
|
+ // The new rpath is empty and there is no rpath anyway so it is
|
|
|
+ // okay.
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (emsg) {
|
|
|
+ *emsg =
|
|
|
+ cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
|
|
|
+ elf.GetErrorMessage());
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+};
|
|
|
+}
|
|
|
+
|
|
|
+bool cmSystemTools::ChangeRPath(std::string const& file,
|
|
|
+ std::string const& oldRPath,
|
|
|
+ std::string const& newRPath,
|
|
|
+ bool removeEnvironmentRPath, std::string* emsg,
|
|
|
+ bool* changed)
|
|
|
+{
|
|
|
+ auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath](
|
|
|
+ cm::optional<std::string>& outRPath,
|
|
|
+ const std::string& inRPath, const char* se_name,
|
|
|
+ std::string* emsg2) -> bool {
|
|
|
+ // Make sure the current rpath contains the old rpath.
|
|
|
+ std::string::size_type pos = cmSystemToolsFindRPath(inRPath, oldRPath);
|
|
|
+ if (pos == std::string::npos) {
|
|
|
+ // If it contains the new rpath instead then it is okay.
|
|
|
+ if (cmSystemToolsFindRPath(inRPath, newRPath) != std::string::npos) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (emsg2) {
|
|
|
+ std::ostringstream e;
|
|
|
+ /* clang-format off */
|
|
|
+ e << "The current " << se_name << " is:\n"
|
|
|
+ << " " << inRPath << "\n"
|
|
|
+ << "which does not contain:\n"
|
|
|
+ << " " << oldRPath << "\n"
|
|
|
+ << "as was expected.";
|
|
|
+ /* clang-format on */
|
|
|
+ *emsg2 = e.str();
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 && inRPath[pos - 1] == ':' &&
|
|
|
+ pos + oldRPath.length() == inRPath.length()) {
|
|
|
+ prefix_len--;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Construct the new value which preserves the part of the path
|
|
|
+ // not being changed.
|
|
|
+ outRPath.emplace();
|
|
|
+ if (!removeEnvironmentRPath) {
|
|
|
+ *outRPath += inRPath.substr(0, prefix_len);
|
|
|
+ }
|
|
|
+ *outRPath += newRPath;
|
|
|
+ *outRPath += inRPath.substr(pos + oldRPath.length());
|
|
|
+
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+
|
|
|
+ return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
|
|
|
+ changed);
|
|
|
+}
|
|
|
#elif defined(CMake_USE_XCOFF_PARSER)
|
|
|
bool cmSystemTools::ChangeRPath(std::string const& file,
|
|
|
std::string const& oldRPath,
|