Refactor: Break up logic in cmSystemTools::ChangeRPath()

This commit is contained in:
Kyle Edwards
2021-05-04 16:21:21 -04:00
parent 2ef3ea394f
commit 966f7250df

View File

@@ -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);
}
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;
}
// 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.");
}
// Adjust the rpath.
cm::optional<std::string> outRPath;
if (!adjustCallback(outRPath, se[i]->Value, se_name[i], emsg)) {
return false;
}
// This entry is ready for update.
++rp_count;
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 < outRPath->length() + 1) {
if (emsg) {
*emsg = cmStrCat("The replacement path is too long for the ",
se_name[i], " entry.");
}
return false;
}
// 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,