[education/rkward] rkward/rbackend: Confine all qt-related stuff to its own library

Thomas Friedrichsmeier null at kde.org
Fri May 10 17:04:24 BST 2024


Git commit f06f2904cae6104601f3f5a3ca980ad968fc9d68 by Thomas Friedrichsmeier.
Committed on 06/05/2024 at 14:54.
Pushed by tfry into branch 'master'.

Confine all qt-related stuff to its own library

M  +16   -12   rkward/rbackend/CMakeLists.txt
M  +4    -23   rkward/rbackend/rkrapi.cpp
M  +1    -1    rkward/rbackend/rkrapi.h
A  +35   -0    rkward/rbackend/rkrbackend_dlopen.cpp     [License: GPL(v2.0+)]
M  +13   -5    rkward/rbackend/rkrbackendprotocol_backend.cpp
M  +9    -0    rkward/rbackend/rkrbackendprotocol_backend.h
M  +1    -0    rkward/rbackend/rkwarddevice/CMakeLists.txt

https://invent.kde.org/education/rkward/-/commit/f06f2904cae6104601f3f5a3ca980ad968fc9d68

diff --git a/rkward/rbackend/CMakeLists.txt b/rkward/rbackend/CMakeLists.txt
index ad55b8bbe..1c68cf33a 100644
--- a/rkward/rbackend/CMakeLists.txt
+++ b/rkward/rbackend/CMakeLists.txt
@@ -45,23 +45,27 @@ SET (
 
 ADD_LIBRARY(rbackend STATIC ${rbackend_frontend_SRCS} ${rbackend_shared_SRCS})
 TARGET_LINK_LIBRARIES(rbackend rkgraphicsdevice.frontend Qt6::Widgets KF6::TextEditor KF6::WindowSystem)
-IF(${DLOPEN_RLIB})
-TARGET_COMPILE_DEFINITIONS(rbackend PUBLIC RK_DLOPEN_LIBRSO)
-ENDIF()
 
 ADD_DEFINITIONS (-DRKWARD_BACKEND_PATH="${KDE_INSTALL_FULL_LIBEXECDIR}")
 LINK_DIRECTORIES(${R_SHAREDLIBDIR})
 
-ADD_EXECUTABLE(rkward.rbackend ${rbackend_backend_SRCS} ${rbackend_shared_SRCS})
-ECM_MARK_NONGUI_EXECUTABLE(rkward.rbackend)
-TARGET_LINK_LIBRARIES(rkward.rbackend rkgraphicsdevice.backend ${CMAKE_THREAD_LIBS_INIT} Qt6::Network Qt6::Core KF6::I18n)
+# See rkrapi.h for documentation and rationale of the linking strategy
 IF(${DLOPEN_RLIB})
-	IF(NOT WIN32)
-	TARGET_LINK_LIBRARIES(rkward.rbackend dl)
-	ENDIF()
-ELSE()
-TARGET_LINK_LIBRARIES(rkward.rbackend ${R_USED_LIBS})
-ENDIF()
+  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)
+  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})
+  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})
+ECM_MARK_NONGUI_EXECUTABLE(rkward.rbackend)
 
 IF(WIN32)
 # 64MB stack size is what R itself is build with on Windows, while by default the stack size would be 1MB
diff --git a/rkward/rbackend/rkrapi.cpp b/rkward/rbackend/rkrapi.cpp
index 9918fe8a7..f2b84bc24 100644
--- a/rkward/rbackend/rkrapi.cpp
+++ b/rkward/rbackend/rkrapi.cpp
@@ -15,35 +15,16 @@ SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "../debug.h"
 
-void RFn::init(const char* libname) {
+void RFn::init(void* libr_dll_handle, void* (*dlsym_fun)(void*, const char*)) {
 #if defined RK_DLOPEN_LIBRSO
-//#if defined(RTLD_DEEPBIND)  // causes hard fail on suse tumbleweed 05/2024
-//	RK_DEBUG(RBACKEND, DL_DEBUG, "Now loading R lib, dynamically (deepbind)");
-//	RFn::init(dlopen(RLIBNAME, RTLD_NOW | RTLD_DEEPBIND));
-//#else
-	RK_DEBUG(RBACKEND, DL_DEBUG, "Now loading R lib, dynamically (local)");
-#if defined(Q_OS_WIN)
-	auto dllinfo = LoadLibraryA(libname);
-#else
-	auto dllinfo = dlopen(libname, RTLD_NOW | RTLD_LOCAL);
-#endif
-	if (!dllinfo) {
-		RK_DEBUG(RBACKEND, DL_ERROR, "Failure loading R lib from '%s'", libname);
-	}
-//#endif
-
 	auto rfn = new RFn(); // we need a dummy object, even if we are only interested in the static members
 	auto meta = rfn->metaObject();
-	RK_DEBUG(RBACKEND, DL_DEBUG, "Loading %d symbols from R lib %p", meta->propertyCount() - meta->propertyOffset(), dllinfo);
+	RK_DEBUG(RBACKEND, DL_DEBUG, "Loading %d symbols from R lib %p", meta->propertyCount() - meta->propertyOffset(), libr_dll_handle);
 	for (int i = meta->propertyOffset(); i < meta->propertyCount(); ++i) {
 		auto prop = meta->property(i);
 		auto name = prop.name();
-#if defined(Q_OS_WIN)
-		auto symb = GetProcAddress(dllinfo, name);
-#else
-		auto symb = dlsym(dllinfo, name);
-#endif
-		RK_DEBUG(RBACKEND, DL_DEBUG, "Lookup of symbol %s in %p: %p", name, dllinfo, symb);
+		auto symb = dlsym_fun(libr_dll_handle, name);
+		RK_DEBUG(RBACKEND, DL_DEBUG, "Lookup of symbol %s in %p: %p", name, libr_dll_handle, symb);
 		prop.write(rfn, QVariant::fromValue((void*) symb)); // NOTE: Qt refuses to write nullptr as value, but that's already the initial value of each member
 	}
 #else
diff --git a/rkward/rbackend/rkrapi.h b/rkward/rbackend/rkrapi.h
index bdb718ce1..0091f0cd4 100644
--- a/rkward/rbackend/rkrapi.h
+++ b/rkward/rbackend/rkrapi.h
@@ -326,7 +326,7 @@ IMPORT_R_API(R_GE_maskType);
 #endif
 
 public:
-	static void init(const char* dllname);
+	static void init(void* libr_dll_handle, void* (*dlsym_fun)(void*, const char*));
 };
 
 #endif
diff --git a/rkward/rbackend/rkrbackend_dlopen.cpp b/rkward/rbackend/rkrbackend_dlopen.cpp
new file mode 100644
index 000000000..2e403677e
--- /dev/null
+++ b/rkward/rbackend/rkrbackend_dlopen.cpp
@@ -0,0 +1,35 @@
+/*
+rkrbackend_dlopen - This file is part of RKWard (https://rkward.kde.org). Created: Mon May 06 2024
+SPDX-FileCopyrightText: 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
+*/
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+void *resolve_symb(void* dllinfo, const char* name) {
+#if defined(Q_OS_WIN)
+	retrun GetProcAddress(dllinfo, name);
+#else
+	return dlsym(dllinfo, name);
+#endif
+}
+
+int main(int argc, char *argv[]) {
+// TODO: Debugging!
+// TODO: Take lib name from CMake?
+#ifdef Q_OS_WIN
+	auto r_dllinfo = LoadLibraryA("R.dll");
+	auto rkb_dllinfo = LoadLibraryA("rkward.rbackend.lib.dll");
+#else
+	auto r_dllinfo = dlopen("libR.so", RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
+	auto rkb_dllinfo = dlopen("librkward.rbackend.lib.so", RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
+#endif
+	int (*do_main) (int, char**, void*, void* (*)(void*, const char*));
+	do_main = (decltype(do_main)) resolve_symb(rkb_dllinfo, "do_main");
+	return do_main(argc, argv, r_dllinfo, resolve_symb);
+}
diff --git a/rkward/rbackend/rkrbackendprotocol_backend.cpp b/rkward/rbackend/rkrbackendprotocol_backend.cpp
index 8f4a7d721..6f8dfebb8 100644
--- a/rkward/rbackend/rkrbackendprotocol_backend.cpp
+++ b/rkward/rbackend/rkrbackendprotocol_backend.cpp
@@ -58,7 +58,17 @@ SPDX-License-Identifier: GPL-2.0-or-later
 		RKDebugMessageOutput (QtDebugMsg, QMessageLogContext (), buffer);
 	}
 
+#ifdef RK_DLOPEN_LIBRSO
+	extern "C"
+#	ifdef Q_OS_WIN
+	__declspec(dllexport)
+#	else
+	__attribute__((__visibility__("default")))
+#endif
+	int do_main(int argc, char *argv[], void* libr_dll_handle, void* (*dlsym_fun)(void*, const char*)) {
+#else
 	int main(int argc, char *argv[]) {
+#endif
 #ifdef Q_OS_MACOS
 		CFBundleRef mainBundle = CFBundleGetMainBundle();
 		if (mainBundle) {
@@ -112,12 +122,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
 
 		// TODO: Should rather take the libname from CMake
 		// maybe we also want to accept an absolute path specified on command line from the frontend
-#ifdef Q_OS_WIN
-#	define RLIBNAME "R.dll"
-#else
-#	define RLIBNAME "libR.so"
+#ifdef RK_DLOPEN_LIBRSO
+		RFn::init(libr_dll_handle, dlsym_fun);
 #endif
-		RFn::init(RLIBNAME);
 
 		RKRBackendTransmitter transmitter (servername, token);
 		RKRBackendProtocolBackend::p_transmitter = &transmitter;
@@ -127,6 +134,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 		// NOTE:: Since some unknown version of R (4.3.0 at the latest, but probably much earlier), run_Rmainloop() does not return, it will
 		//        eventually exit, instead.
 		RKRBackendProtocolBackend::doExit();
+		return 0;
 	}
 
 	void RKRBackendProtocolBackend::doExit() {
diff --git a/rkward/rbackend/rkrbackendprotocol_backend.h b/rkward/rbackend/rkrbackendprotocol_backend.h
index 8ff354738..076ac6871 100644
--- a/rkward/rbackend/rkrbackendprotocol_backend.h
+++ b/rkward/rbackend/rkrbackendprotocol_backend.h
@@ -13,6 +13,14 @@ SPDX-License-Identifier: GPL-2.0-or-later
 class QThread;
 class RKRBackendTransmitter;
 
+extern "C"
+#ifdef Q_OS_WIN
+	__declspec(dllexport)
+#else
+	__attribute__((__visibility__("default")))
+#endif
+int do_main(int, char**, void*, void* (*)(void*, const char*));
+
 class RKRBackendProtocolBackend {
 public:
 	static bool inRThread ();
@@ -29,6 +37,7 @@ friend class RKRBackend;
 friend class RKRBackendThread;
 friend class RKRBackendTransmitter;
 friend int main(int, char**);
+friend int do_main(int, char**, void*, void* (*)(void*, const char*));
 	void sendRequest (RBackendRequest *request);
 	static void msleep (int delay);
 	static RKRBackendProtocolBackend* instance () { return _instance; };
diff --git a/rkward/rbackend/rkwarddevice/CMakeLists.txt b/rkward/rbackend/rkwarddevice/CMakeLists.txt
index 90687e278..08d57b12a 100644
--- a/rkward/rbackend/rkwarddevice/CMakeLists.txt
+++ b/rkward/rbackend/rkwarddevice/CMakeLists.txt
@@ -24,4 +24,5 @@ ADD_LIBRARY(rkgraphicsdevice.backend STATIC ${rkgraphicsdevice_backend_SRCS})
 TARGET_LINK_LIBRARIES(rkgraphicsdevice.backend Qt6::Core Qt6::Network)
 IF(${DLOPEN_RLIB})
 TARGET_COMPILE_DEFINITIONS(rkgraphicsdevice.backend PUBLIC RK_DLOPEN_LIBRSO)
+TARGET_COMPILE_OPTIONS(rkgraphicsdevice.backend PUBLIC -fPIC)
 ENDIF()



More information about the rkward-tracker mailing list