1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-15 20:46:37 +08:00

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.
This commit is contained in:
Alex Richardson
2021-06-14 19:57:59 +01:00
committed by Brad King
parent 5ef8c09a8f
commit 2e1149874d

View File

@@ -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. cm::optional<bool> AdjustRPathELF(std::string const& file,
bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback, const EmptyCallback& emptyCallback,
const AdjustCallback& adjustCallback, std::string* emsg, const AdjustCallback& adjustCallback,
bool* changed) 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, cm::optional<bool> ChangeRPathELF(std::string const& file,
std::string const& oldRPath, std::string const& oldRPath,
std::string const& newRPath, std::string const& newRPath,
bool removeEnvironmentRPath, std::string* emsg, bool removeEnvironmentRPath,
bool* changed) 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, return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback,
changed); emsg, changed);
} }
bool cmSystemTools::SetRPath(std::string const& file, static cm::optional<bool> SetRPathELF(std::string const& file,
std::string const& newRPath, std::string* emsg, std::string const& newRPath,
bool* changed) 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, return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback,
changed); emsg, changed);
} }
#elif defined(CMake_USE_XCOFF_PARSER) static cm::optional<bool> ChangeRPathXCOFF(std::string const& file,
bool cmSystemTools::ChangeRPath(std::string const& file, std::string const& oldRPath,
std::string const& oldRPath, std::string const& newRPath,
std::string const& newRPath, bool removeEnvironmentRPath,
bool removeEnvironmentRPath, std::string* emsg, std::string* emsg, bool* changed)
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;
}
bool cmSystemTools::SetRPath(std::string const& /*file*/,
std::string const& /*newRPath*/,
std::string* /*emsg*/, bool* /*changed*/)
{
return false;
}
#else
bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
std::string const& /*oldRPath*/,
std::string const& /*newRPath*/,
bool /*removeEnvironmentRPath*/,
std::string* /*emsg*/, bool* /*changed*/)
{
return false;
}
bool cmSystemTools::SetRPath(std::string const& /*file*/,
std::string const& /*newRPath*/,
std::string* /*emsg*/, bool* /*changed*/)
{
return false;
}
#endif #endif
}
static cm::optional<bool> SetRPathXCOFF(std::string const& /*file*/,
std::string const& /*newRPath*/,
std::string* /*emsg*/,
bool* /*changed*/)
{
return cm::nullopt; // Not implemented.
}
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;
}
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;
}
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. static cm::optional<bool> RemoveRPathELF(std::string const& file,
#if defined(CMake_USE_ELF_PARSER) std::string* emsg, bool* removed)
bool cmSystemTools::RemoveRPath(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, static cm::optional<bool> RemoveRPathXCOFF(std::string const& file,
bool* removed) 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 cmSystemTools::RemoveRPath(std::string const& /*file*/, bool* removed)
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());
if (elf) {
// Get the RPATH or RUNPATH entry from it. // Get the RPATH or RUNPATH entry from it.
cmELF::StringEntry const* se = elf.GetRPath(); cmELF::StringEntry const* se = elf.GetRPath();
if (!se) {
se = elf.GetRunPath();
}
// Make sure the current rpath contains the new rpath.
if (newRPath.empty()) {
if (!se) { if (!se) {
return true; se = elf.GetRunPath();
} }
} else {
if (se && // Make sure the current rpath contains the new rpath.
cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) { if (newRPath.empty()) {
return true; if (!se) {
return true;
}
} else {
if (se &&
cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) {
return true;
}
} }
return false;
} }
return false; #endif
#elif defined(CMake_USE_XCOFF_PARSER) #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 (xcoff) {
if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) { if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) {
return true; if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) {
return true;
}
} }
return false;
} }
return false; #endif
#else
(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)