Skip to content

Commit 3691e9e

Browse files
committed
Copy, patch and monitor external binary plugins
1 parent 3317129 commit 3691e9e

File tree

8 files changed

+264
-231
lines changed

8 files changed

+264
-231
lines changed

cmake/detect_dependencies.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ endif()
234234
# #### patchelf
235235
# ###############################
236236
message(STATUS "using patchelf from deps")
237+
add_subdirectory(deps/patchelf)
237238
add_library(patchelf::patchelf INTERFACE IMPORTED)
238239
set_target_properties(patchelf::patchelf PROPERTIES
239240
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/deps/patchelf"

deps/patchelf/CMakeLists.txt

+21-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
# minimum required cmake version
22
cmake_minimum_required(VERSION 3.0)
33

4-
set(PATCHELF_SRC patchelf.cc)
5-
set(PATCHELF_HDR elf.h patchelf.h)
4+
set(PATCHELF_DIR patchelf)
5+
set(PATCHELF_SRC ${PATCHELF_DIR}/patchelf.cc)
6+
set(PATCHELF_HDR ${PATCHELF_DIR}/elf.h ${PATCHELF_DIR}/patchelf.h)
67

7-
add_library (patchelf::patchelf SHARED ${PATCHELF_SRC})
8+
add_library (patchelf SHARED ${PATCHELF_SRC})
89

9-
target_include_directories(patchelf::patchelf PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>"
10-
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
10+
target_include_directories(patchelf PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/patchelf>"
11+
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
1112

13+
install(TARGETS patchelf
14+
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIRECTORY}
15+
PERMISSIONS
16+
OWNER_READ
17+
OWNER_WRITE
18+
OWNER_EXECUTE
19+
GROUP_READ
20+
GROUP_EXECUTE
21+
WORLD_READ
22+
WORLD_EXECUTE
23+
)
24+
25+
set_target_properties(patchelf PROPERTIES
26+
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/deps/patchelf"
27+
)
File renamed without changes.

deps/patchelf/patchelf.cc renamed to deps/patchelf/patchelf/patchelf.cc

+27-187
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ static bool clobberOldSections = true;
6363
static std::vector<std::string> fileNames;
6464
static std::string outputFileName;
6565
static bool alwaysWrite = false;
66+
static std::string oldRPath;
67+
static std::vector<std::string> neededLibraries;
6668
#ifdef DEFAULT_PAGESIZE
6769
static int forcedPageSize = DEFAULT_PAGESIZE;
6870
#else
@@ -1645,7 +1647,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
16451647

16461648
switch (op) {
16471649
case rpPrint: {
1648-
printf("%s\n", rpath ? rpath : "");
1650+
oldRPath = std::string(rpath ? rpath : "");
16491651
return;
16501652
}
16511653
case rpRemove: {
@@ -1968,6 +1970,7 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
19681970
template<ElfFileParams>
19691971
void ElfFile<ElfFileParamNames>::printNeededLibs() const
19701972
{
1973+
neededLibraries.clear();
19711974
const auto shdrDynamic = findSectionHeader(".dynamic");
19721975
const auto shdrDynStr = findSectionHeader(".dynstr");
19731976
const char *strTab = (const char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
@@ -1977,7 +1980,7 @@ void ElfFile<ElfFileParamNames>::printNeededLibs() const
19771980
for (; rdi(dyn->d_tag) != DT_NULL; dyn++) {
19781981
if (rdi(dyn->d_tag) == DT_NEEDED) {
19791982
const char *name = strTab + rdi(dyn->d_un.d_val);
1980-
printf("%s\n", name);
1983+
neededLibraries.push_back(name);
19811984
}
19821985
}
19831986
}
@@ -2569,196 +2572,33 @@ static void showHelp(const std::string & progName)
25692572
FILENAME...\n", progName.c_str());
25702573
}
25712574

2572-
2573-
static int mainWrapped(int argc, char * * argv)
2575+
std::string patchelf::get_rpath(const std::string& filename)
25742576
{
2575-
if (argc <= 1) {
2576-
showHelp(argv[0]);
2577-
return 1;
2578-
}
2579-
2580-
if (getenv("PATCHELF_DEBUG") != nullptr)
2581-
debugMode = true;
2582-
2583-
int i;
2584-
for (i = 1; i < argc; ++i) {
2585-
std::string arg(argv[i]);
2586-
if (arg == "--set-interpreter" || arg == "--interpreter") {
2587-
if (++i == argc) error("missing argument");
2588-
newInterpreter = resolveArgument(argv[i]);
2589-
}
2590-
else if (arg == "--page-size") {
2591-
if (++i == argc) error("missing argument");
2592-
forcedPageSize = atoi(argv[i]);
2593-
if (forcedPageSize <= 0) error("invalid argument to --page-size");
2594-
}
2595-
else if (arg == "--print-interpreter") {
2596-
printInterpreter = true;
2597-
}
2598-
else if (arg == "--print-os-abi") {
2599-
printOsAbi = true;
2600-
}
2601-
else if (arg == "--set-os-abi") {
2602-
if (++i == argc) error("missing argument");
2603-
setOsAbi = true;
2604-
newOsAbi = resolveArgument(argv[i]);
2605-
}
2606-
else if (arg == "--print-soname") {
2607-
printSoname = true;
2608-
}
2609-
else if (arg == "--set-soname") {
2610-
if (++i == argc) error("missing argument");
2611-
setSoname = true;
2612-
newSoname = resolveArgument(argv[i]);
2613-
}
2614-
else if (arg == "--remove-rpath") {
2615-
removeRPath = true;
2616-
}
2617-
else if (arg == "--shrink-rpath") {
2618-
shrinkRPath = true;
2619-
}
2620-
else if (arg == "--allowed-rpath-prefixes") {
2621-
if (++i == argc) error("missing argument");
2622-
allowedRpathPrefixes = splitColonDelimitedString(argv[i]);
2623-
}
2624-
else if (arg == "--set-rpath") {
2625-
if (++i == argc) error("missing argument");
2626-
setRPath = true;
2627-
newRPath = resolveArgument(argv[i]);
2628-
}
2629-
else if (arg == "--add-rpath") {
2630-
if (++i == argc) error("missing argument");
2631-
addRPath = true;
2632-
newRPath = resolveArgument(argv[i]);
2633-
}
2634-
else if (arg == "--print-rpath") {
2635-
printRPath = true;
2636-
}
2637-
else if (arg == "--force-rpath") {
2638-
/* Generally we prefer to emit DT_RUNPATH instead of
2639-
DT_RPATH, as the latter is obsolete. However, there is
2640-
a slight semantic difference: DT_RUNPATH is "scoped",
2641-
it only affects the executable or library in question,
2642-
not its recursive imports. So maybe you really want to
2643-
force the use of DT_RPATH. That's what this option
2644-
does. Without it, DT_RPATH (if encountered) is
2645-
converted to DT_RUNPATH, and if neither is present, a
2646-
DT_RUNPATH is added. With it, DT_RPATH isn't converted
2647-
to DT_RUNPATH, and if neither is present, a DT_RPATH is
2648-
added. */
2649-
forceRPath = true;
2650-
}
2651-
else if (arg == "--print-needed") {
2652-
printNeeded = true;
2653-
}
2654-
else if (arg == "--no-sort") {
2655-
noSort = true;
2656-
}
2657-
else if (arg == "--add-needed") {
2658-
if (++i == argc) error("missing argument");
2659-
neededLibsToAdd.insert(resolveArgument(argv[i]));
2660-
}
2661-
else if (arg == "--remove-needed") {
2662-
if (++i == argc) error("missing argument");
2663-
neededLibsToRemove.insert(resolveArgument(argv[i]));
2664-
}
2665-
else if (arg == "--replace-needed") {
2666-
if (i+2 >= argc) error("missing argument(s)");
2667-
neededLibsToReplace[ argv[i+1] ] = argv[i+2];
2668-
i += 2;
2669-
}
2670-
else if (arg == "--clear-symbol-version") {
2671-
if (++i == argc) error("missing argument");
2672-
symbolsToClearVersion.insert(resolveArgument(argv[i]));
2673-
}
2674-
else if (arg == "--print-execstack") {
2675-
printExecstack = true;
2676-
}
2677-
else if (arg == "--clear-execstack") {
2678-
clearExecstack = true;
2679-
}
2680-
else if (arg == "--set-execstack") {
2681-
setExecstack = true;
2682-
}
2683-
else if (arg == "--output") {
2684-
if (++i == argc) error("missing argument");
2685-
outputFileName = resolveArgument(argv[i]);
2686-
alwaysWrite = true;
2687-
}
2688-
else if (arg == "--debug") {
2689-
debugMode = true;
2690-
}
2691-
else if (arg == "--no-default-lib") {
2692-
noDefaultLib = true;
2693-
}
2694-
else if (arg == "--add-debug-tag") {
2695-
addDebugTag = true;
2696-
}
2697-
else if (arg == "--rename-dynamic-symbols") {
2698-
renameDynamicSymbols = true;
2699-
if (++i == argc) error("missing argument");
2700-
2701-
const char* fname = argv[i];
2702-
std::ifstream infile(fname);
2703-
if (!infile) error(fmt("Cannot open map file ", fname));
2704-
2705-
std::string line, from, to;
2706-
size_t lineCount = 1;
2707-
while (std::getline(infile, line))
2708-
{
2709-
std::istringstream iss(line);
2710-
if (!(iss >> from))
2711-
break;
2712-
if (!(iss >> to))
2713-
error(fmt(fname, ":", lineCount, ": Map file line is missing the second element"));
2714-
if (symbolsToRenameKeys.count(from))
2715-
error(fmt(fname, ":", lineCount, ": Name '", from, "' appears twice in the map file"));
2716-
if (from.find('@') != std::string_view::npos || to.find('@') != std::string_view::npos)
2717-
error(fmt(fname, ":", lineCount, ": Name pair contains version tag: ", from, " ", to));
2718-
lineCount++;
2719-
symbolsToRename[*symbolsToRenameKeys.insert(from).first] = to;
2720-
}
2721-
}
2722-
else if (arg == "--no-clobber-old-sections") {
2723-
clobberOldSections = false;
2724-
}
2725-
else if (arg == "--help" || arg == "-h" ) {
2726-
showHelp(argv[0]);
2727-
return 0;
2728-
}
2729-
else if (arg == "--version") {
2730-
printf(PACKAGE_STRING "\n");
2731-
return 0;
2732-
}
2733-
else {
2734-
fileNames.push_back(arg);
2735-
}
2736-
}
2737-
2738-
if (fileNames.empty()) error("missing filename");
2739-
2740-
if (!outputFileName.empty() && fileNames.size() != 1)
2741-
error("--output option only allowed with single input file");
2742-
2743-
if (setRPath && addRPath)
2744-
error("--set-rpath option not allowed with --add-rpath");
2745-
2577+
fileNames.push_back(filename);
2578+
printRPath = true;
27462579
patchElf();
2580+
return oldRPath;
2581+
}
27472582

2748-
return 0;
2583+
void patchelf::set_rpath(const std::string& filename, const std::string& rp)
2584+
{
2585+
fileNames.push_back(filename);
2586+
setRPath = true;
2587+
newRPath = rp;
2588+
patchElf();
27492589
}
27502590

2751-
int main(int argc, char * * argv)
2591+
std::vector<std::string> patchelf::get_needed_libraries(const std::string& filename)
27522592
{
2753-
#ifdef __OpenBSD__
2754-
if (pledge("stdio rpath wpath cpath", NULL) == -1)
2755-
error("pledge");
2756-
#endif
2593+
fileNames.push_back(filename);
2594+
printNeeded = true;
2595+
patchElf();
2596+
return neededLibraries;
2597+
}
27572598

2758-
try {
2759-
return mainWrapped(argc, argv);
2760-
} catch (std::exception & e) {
2761-
fprintf(stderr, "patchelf: %s\n", e.what());
2762-
return 1;
2763-
}
2599+
void patchelf::replace_needed_library(const std::string& filename, const std::string& oldLib, const std::string& newLib)
2600+
{
2601+
fileNames.push_back(filename);
2602+
neededLibsToReplace[oldLib] = newLib;
2603+
patchElf();
27642604
}

deps/patchelf/patchelf.h renamed to deps/patchelf/patchelf/patchelf.h

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88

99
#include "elf.h"
1010

11+
namespace patchelf {
12+
std::string get_rpath(const std::string& filename);
13+
void set_rpath(const std::string& filename, const std::string& rp);
14+
std::vector<std::string> get_needed_libraries(const std::string& filename);
15+
void replace_needed_library(const std::string& filename, const std::string& oldLib, const std::string& newLib);
16+
}
17+
1118
using FileContents = std::shared_ptr<std::vector<unsigned char>>;
1219

1320
#define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym, class Elf_Versym, class Elf_Verdef, class Elf_Verdaux, class Elf_Verneed, class Elf_Vernaux, class Elf_Rel, class Elf_Rela, unsigned ElfClass

plugins/gui/CMakeLists.txt

+1-3
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,6 @@ if(PL_GUI OR BUILD_ALL_PLUGINS)
7676
message(STATUS "Using system's quazip from ${QUAZIP_LIBRARIES}")
7777
endif()
7878

79-
add_subdirectory(patchelf::patchelf)
80-
8179
foreach(i IN ITEMS "" "_DEBUG" "_RELEASE" "_MINSIZEREL" "_RELWITHDEBINFO")
8280
foreach(j IN ITEMS "RUNTIME" "ARCHIVE" "LIBRARY")
8381
set(CMAKE_${j}_OUTPUT_DIRECTORY${i} ${STORE_${j}_OUTDIR${i}})
@@ -116,7 +114,7 @@ if(PL_GUI OR BUILD_ALL_PLUGINS)
116114
PRIVATE ${COMPILE_OPTIONS_PRIVATE}
117115
INTERFACE ${COMPILE_OPTIONS_INTERFACE})
118116
target_compile_definitions(gui PUBLIC QT_NO_KEYWORDS)
119-
target_link_libraries(gui PUBLIC hal::core hal::netlist PRIVATE ${Python3_LIBRARIES} pybind11::embed Qt5::Widgets Qt5::Concurrent Qt5::Svg QuaZip::QuaZip)
117+
target_link_libraries(gui PUBLIC hal::core hal::netlist PRIVATE ${Python3_LIBRARIES} pybind11::embed Qt5::Widgets Qt5::Concurrent Qt5::Svg QuaZip::QuaZip patchelf)
120118
add_dependencies(gui update_internal_gate_library_definitions)
121119
get_property(GLDIR GLOBAL PROPERTY GATE_LIBS_DEFINITIONS)
122120
file(WRITE "${RSRCROOT}/path/gate_library_definitions.txt" "${GLDIR}")

plugins/gui/include/gui/plugin_relay/gui_plugin_manager.h

+23-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <QTableView>
3737
#include <QItemDelegate>
3838
#include <QMenu>
39+
#include <QFileSystemWatcher>
3940

4041
#include "gui/gui_utils/netlist.h"
4142
#include "hal_core/plugin_system/plugin_manager.h"
@@ -48,6 +49,25 @@ class QPushButton;
4849
namespace hal {
4950
class GuiExtensionInterface;
5051

52+
class ExternalBinaryPlugin : public QObject
53+
{
54+
Q_OBJECT
55+
QString mPluginName;
56+
QString mSourcePath;
57+
QString mTargetPath;
58+
enum DirectoryType { UnknownDir, LibDir, PluginDir };
59+
static QString libquazipName();
60+
QMultiMap<DirectoryType, QString> getLibraryRpath() const;
61+
static QString halLibraryPath(DirectoryType dirType);
62+
public:
63+
QFileSystemWatcher* mFileWatcher;
64+
ExternalBinaryPlugin(const QString& plugName, const QString& filename);
65+
QString sourcePath() const { return mSourcePath; }
66+
QString targetPath() const { return mTargetPath; }
67+
QString pluginName() const { return mPluginName; }
68+
void updateLibraryPath();
69+
};
70+
5171
class GuiPluginEntry
5272
{
5373
public:
@@ -57,7 +77,7 @@ namespace hal {
5777
QString mVersion;
5878
QString mDescription;
5979
QString mFilePath;
60-
QString mExternalPath;
80+
ExternalBinaryPlugin* mExternalBinaryPlugin;
6181
QDateTime mFileModified;
6282
QStringList mDependencies;
6383
FacExtensionInterface::Feature mFeature;
@@ -70,6 +90,7 @@ namespace hal {
7090
public:
7191
GuiPluginEntry(const QFileInfo& info);
7292
GuiPluginEntry(const QSettings* settings);
93+
~GuiPluginEntry();
7394
QVariant data(int icol) const;
7495
QString name() const { return mName; }
7596
void persist(QSettings* settings) const;
@@ -137,6 +158,7 @@ namespace hal {
137158
void handlePluginLoaded(const QString& pluginName, const QString& path);
138159
void handlePluginUnloaded(const QString& pluginName, const QString& path);
139160
void handleRefresh();
161+
void handleExternalBinaryPluginChanged();
140162
public:
141163
GuiPluginTable(GuiPluginManager* parent = nullptr);
142164
~GuiPluginTable();
@@ -202,7 +224,6 @@ namespace hal {
202224
QColor mHilightBackgroundColor;
203225
QLabel* mIconLegend[4];
204226

205-
void setLdLibraryPath();
206227
Q_SIGNALS:
207228
void backToNetlist();
208229
private Q_SLOTS:

0 commit comments

Comments
 (0)