[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