[education/rkward] rkward/rbackend: Remove accidental shared linkage, help dlopen along
Thomas Friedrichsmeier
null at kde.org
Fri May 10 17:04:24 BST 2024
Git commit eab7143038084a64a22e105e22a97fb695a20baf by Thomas Friedrichsmeier.
Committed on 09/05/2024 at 13:01.
Pushed by tfry into branch 'master'.
Remove accidental shared linkage, help dlopen along
M +2 -2 rkward/rbackend/CMakeLists.txt
M +26 -2 rkward/rbackend/rkfrontendtransmitter.cpp
M +27 -3 rkward/rbackend/rkrbackend_dlopen.cpp
M +1 -1 rkward/rbackend/rkrbackendprotocol_backend.cpp
M +26 -21 rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
https://invent.kde.org/education/rkward/-/commit/eab7143038084a64a22e105e22a97fb695a20baf
diff --git a/rkward/rbackend/CMakeLists.txt b/rkward/rbackend/CMakeLists.txt
index 1c68cf33a..9edfeed49 100644
--- a/rkward/rbackend/CMakeLists.txt
+++ b/rkward/rbackend/CMakeLists.txt
@@ -47,21 +47,21 @@ ADD_LIBRARY(rbackend STATIC ${rbackend_frontend_SRCS} ${rbackend_shared_SRCS})
TARGET_LINK_LIBRARIES(rbackend rkgraphicsdevice.frontend Qt6::Widgets KF6::TextEditor KF6::WindowSystem)
ADD_DEFINITIONS (-DRKWARD_BACKEND_PATH="${KDE_INSTALL_FULL_LIBEXECDIR}")
-LINK_DIRECTORIES(${R_SHAREDLIBDIR})
# See rkrapi.h for documentation and rationale of the linking strategy
IF(${DLOPEN_RLIB})
ADD_LIBRARY(rkward.rbackend.lib SHARED ${rbackend_backend_SRCS} ${rbackend_shared_SRCS})
TARGET_LINK_LIBRARIES(rkward.rbackend.lib rkgraphicsdevice.backend ${CMAKE_THREAD_LIBS_INIT} Qt6::Network Qt6::Core KF6::I18n)
TARGET_COMPILE_DEFINITIONS(rkward.rbackend.lib PUBLIC RK_DLOPEN_LIBRSO)
+ TARGET_COMPILE_DEFINITIONS(rbackend PUBLIC RK_DLOPEN_LIBRSO)
INSTALL(TARGETS rkward.rbackend.lib DESTINATION ${KDE_INSTALL_LIBDIR})
ADD_EXECUTABLE(rkward.rbackend rkrbackend_dlopen.cpp)
- TARGET_LINK_LIBRARIES(rkward.rbackend rkward.rbackend.lib)
IF(NOT WIN32)
TARGET_LINK_LIBRARIES(rkward.rbackend dl)
ENDIF()
ELSE(${DLOPEN_RLIB})
+ LINK_DIRECTORIES(${R_SHAREDLIBDIR})
ADD_EXECUTABLE(rkward.rbackend ${rbackend_backend_SRCS} ${rbackend_shared_SRCS})
TARGET_LINK_LIBRARIES(rkward.rbackend rkgraphicsdevice.backend ${R_USED_LIBS} ${CMAKE_THREAD_LIBS_INIT} Qt6::Network Qt6::Core KF6::I18n)
ENDIF(${DLOPEN_RLIB})
diff --git a/rkward/rbackend/rkfrontendtransmitter.cpp b/rkward/rbackend/rkfrontendtransmitter.cpp
index 3298ea039..adbffeba6 100644
--- a/rkward/rbackend/rkfrontendtransmitter.cpp
+++ b/rkward/rbackend/rkfrontendtransmitter.cpp
@@ -1,6 +1,6 @@
/*
rkfrontendtransmitter - This file is part of RKWard (https://rkward.kde.org). Created: Thu Nov 04 2010
-SPDX-FileCopyrightText: 2010-2019 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
+SPDX-FileCopyrightText: 2010-2024 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -41,6 +41,23 @@ QString findBackendAtPath (const QString &path) {
return QString ();
}
+#if defined(RK_DLOPEN_LIBRSO)
+QString findBackendLibAtPath(const QString &path) {
+ QDir dir(path);
+ dir.makeAbsolute();
+#ifdef Q_OS_WIN
+ QString ret = dir.filePath("rkward.rbackend.lib.dll");
+#elif defined(Q_OS_MACOS)
+ QString ret = dir.filePath("librkward.rbackend.lib.dylib");
+#else
+ QString ret = dir.filePath("librkward.rbackend.lib.so");
+#endif
+ RK_DEBUG(RBACKEND, DL_DEBUG, "Looking for backend lib at %s", qPrintable(ret));
+ if (QFileInfo(ret).exists()) return ret;
+ return QString();
+}
+#endif
+
bool pathIsChildOf(const QString &parent, const QString &child) {
return QFileInfo(child).canonicalFilePath().startsWith(QFileInfo(parent).canonicalFilePath());
}
@@ -114,7 +131,6 @@ void RKFrontendTransmitter::run () {
removeFromPathList("LD_LIBRARY_PATH", appdir);
removeFromPathList("PATH", appdir);
}
- backend->setEnvironment (env);
QStringList args;
args.append("CMD");
@@ -141,6 +157,14 @@ void RKFrontendTransmitter::run () {
return;
}
+#if defined(RK_DLOPEN_LIBRSO)
+ QString backend_lib = findBackendLibAtPath(QCoreApplication::applicationDirPath()); // for running directly from the build tree, but also covers windows
+ if (backend_lib.isEmpty()) backend_lib = findBackendLibAtPath(QCoreApplication::applicationDirPath() + "../lib"); // covers rkward in /usr[/local]/bin and lib in /usr/[/local]/lib -> regular install on Linux
+ if (backend_lib.isEmpty()) backend_lib = findBackendLibAtPath(QFileInfo(backend_executable).absolutePath()); // backend and lib both installed in libexec or similar
+ env.append(QStringLiteral("RK_BACKEND_LIB=") + backend_lib);
+#endif
+ backend->setEnvironment(env);
+
#ifdef Q_OS_WIN
// Needed for paths with spaces. R CMD is too simple to deal with those, even if we provide proper quoting.
// So rather we need to work from a relative path with all spaces eliminated
diff --git a/rkward/rbackend/rkrbackend_dlopen.cpp b/rkward/rbackend/rkrbackend_dlopen.cpp
index 3c7892f7d..fce369249 100644
--- a/rkward/rbackend/rkrbackend_dlopen.cpp
+++ b/rkward/rbackend/rkrbackend_dlopen.cpp
@@ -5,6 +5,9 @@ SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
+#include <stdlib.h>
+#include <stdio.h>
+
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#define Win32
#endif
@@ -23,16 +26,37 @@ void *resolve_symb(void* dllinfo, const char* name) {
}
int main(int argc, char *argv[]) {
-// TODO: Debugging!
// TODO: Take lib name from CMake?
+// TODO: Use dlmopen, where available?
+ const char* backendlib = getenv("RK_BACKEND_LIB");
+ if (!backendlib) {
+ fprintf(stderr, "Backend lib not specified!");
+ exit(99);
+ }
#ifdef Win32
auto r_dllinfo = LoadLibraryA("R.dll");
- auto rkb_dllinfo = LoadLibraryA("rkward.rbackend.lib.dll");
+ auto rkb_dllinfo = LoadLibraryA(backendlib);
#else
+# ifdef __APPLE__
+ auto r_dllinfo = dlopen("libR.dylib", RTLD_NOW | RTLD_LOCAL);
+# else
auto r_dllinfo = dlopen("libR.so", RTLD_NOW | RTLD_LOCAL); // NOTE: RTLD_DEEPBIND causes undiagnosed runtime failure on Suse Tumbleweed around 05/24 (while it works, elsewhere)
- auto rkb_dllinfo = dlopen("librkward.rbackend.lib.so", RTLD_NOW | RTLD_LOCAL);
+# endif
+ auto rkb_dllinfo = dlopen(backendlib, RTLD_NOW | RTLD_LOCAL);
#endif
+ if (!rkb_dllinfo) {
+ fprintf(stderr, "Failure to open backend lib from %s", backendlib);
+ exit(99);
+ }
+ if (!r_dllinfo) {
+ fprintf(stderr, "Failure to open R lib");
+ exit(99);
+ }
int (*do_main) (int, char**, void*, void* (*)(void*, const char*));
do_main = (decltype(do_main)) resolve_symb(rkb_dllinfo, "do_main");
+ if (!do_main) {
+ fprintf(stderr, "Failure to resolve do_main()");
+ exit(99);
+ }
return do_main(argc, argv, r_dllinfo, resolve_symb);
}
diff --git a/rkward/rbackend/rkrbackendprotocol_backend.cpp b/rkward/rbackend/rkrbackendprotocol_backend.cpp
index 6f8dfebb8..9f80d4bc6 100644
--- a/rkward/rbackend/rkrbackendprotocol_backend.cpp
+++ b/rkward/rbackend/rkrbackendprotocol_backend.cpp
@@ -127,7 +127,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
#endif
RKRBackendTransmitter transmitter (servername, token);
- RKRBackendProtocolBackend::p_transmitter = &transmitter;
+ RKRBackendProtocolBackend::p_transmitter = &transmitter; // cppcheck-suppress danlingReference -> valid for the lifetime of the backend
RKRBackendProtocolBackend backend (data_dir, rkd_server_name);
transmitter.start ();
RKRBackend::this_pointer->run (locale_dir);
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
index 40506598d..4720a93e5 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_setup.cpp
@@ -183,30 +183,35 @@ bool RKGraphicsDeviceDesc::init (pDevDesc dev, double pointsize, const QStringLi
dev->newFrameConfirm = RKD_NewFrameConfirm;
dev->holdflush = RKD_HoldFlush;
-#if R_VERSION >= R_Version (4, 1, 0)
- // patterns and gradients
- dev->setPattern = RKD_SetPattern;
- dev->releasePattern = RKD_ReleasePattern;
- // clipping paths
- dev->setClipPath = RKD_SetClipPath;
- dev->releaseClipPath = RKD_ReleaseClipPath;
- // masks
- dev->setMask = RKD_SetMask;
- dev->releaseMask = RKD_ReleaseMask;
- dev->deviceVersion = qMin(15, R_GE_version);
- dev->deviceClip = TRUE; // for now
+#if R_VERSION >= R_Version (4, 2, 0)
+ // NOTE: We need both a compiletime and a runtime check, in order to support running with an R older than what was used at compile time
+ if (RFn::R_GE_getVersion() >= 15) {
+ // patterns and gradients
+ dev->setPattern = RKD_SetPattern;
+ dev->releasePattern = RKD_ReleasePattern;
+ // clipping paths
+ dev->setClipPath = RKD_SetClipPath;
+ dev->releaseClipPath = RKD_ReleaseClipPath;
+ // masks
+ dev->setMask = RKD_SetMask;
+ dev->releaseMask = RKD_ReleaseMask;
+ dev->deviceVersion = qMin(15, R_GE_version);
+ dev->deviceClip = TRUE; // for now
+ }
#endif
#if R_VERSION >= R_Version (4, 2, 0)
- // groups
- dev->defineGroup = RKD_DefineGroup;
- dev->useGroup = RKD_UseGroup;
- dev->releaseGroup = RKD_ReleaseGroup;
-
- // stroked / filled paths
- dev->stroke = RKD_Stroke;
- dev->fill = RKD_Fill;
- dev->fillStroke = RKD_FillStroke;
+ if (RFn::R_GE_getVersion() >= 16) {
+ // groups
+ dev->defineGroup = RKD_DefineGroup;
+ dev->useGroup = RKD_UseGroup;
+ dev->releaseGroup = RKD_ReleaseGroup;
+
+ // stroked / filled paths
+ dev->stroke = RKD_Stroke;
+ dev->fill = RKD_Fill;
+ dev->fillStroke = RKD_FillStroke;
+ }
#endif
return true;
}
More information about the rkward-tracker
mailing list