[education/rkward] rkward/rbackend: Work around libglib version conflict in AppImage

Thomas Friedrichsmeier null at kde.org
Fri Aug 2 14:16:22 BST 2024


Git commit 00e55dda801bb7aeb06b276970fc71382e33e237 by Thomas Friedrichsmeier.
Committed on 02/08/2024 at 13:16.
Pushed by tfry into branch 'master'.

Work around libglib version conflict in AppImage

M  +35   -3    rkward/rbackend/rkrbackend_dlopen.cpp

https://invent.kde.org/education/rkward/-/commit/00e55dda801bb7aeb06b276970fc71382e33e237

diff --git a/rkward/rbackend/rkrbackend_dlopen.cpp b/rkward/rbackend/rkrbackend_dlopen.cpp
index 2d026f26c..c487b85ef 100644
--- a/rkward/rbackend/rkrbackend_dlopen.cpp
+++ b/rkward/rbackend/rkrbackend_dlopen.cpp
@@ -59,10 +59,40 @@ auto loadlib(const char* name) {
 	return ret;
 }
 
-int main(int argc, char *argv[]) {
-// TODO: Take lib name from CMake?
+#if !(defined(Win32) || defined(__APPLE__))
+auto loadGlib(unsigned int *version) {
+	auto glib = dlopen("libglib-2.0.so", RTLD_LAZY | RTLD_LOCAL);
+	auto glib_verp = static_cast<unsigned int *>(resolve_symb(glib, "glib_minor_version"));
+	*version = glib_verp ? (*glib_verp) : 0;
+	return glib;
+}
+
+/** The backendlib is indirectly linked against libglib-2, so this is also included in the AppImage.
+ *  Certain R libraries, including grDevices.so and cairo.so also link against libglib, in this case the system version.
+ *  This may fail, if the bundle contains a lower version, and this is loaded, first (or vice versa).
+ *  To mitigate the mess, we try to find out, which version appears to be newer, and preload that before our backendlib. */
+void preloadBetterGlib(const char *cd_to) {
+	unsigned int glib1_ver, glib2_ver;
+	auto glib1 = loadGlib(&glib1_ver);
+	dlclose(glib1);
+
+	auto cd = std::filesystem::current_path();
+	if (cd_to && cd_to[0]) {
+		std::filesystem::current_path(cd_to);
+	}
+	auto glib2 = loadGlib(&glib2_ver);
+	std::filesystem::current_path(cd);
+
+	if (glib1_ver >= glib2_ver) {
+		dlclose(glib2);
+		loadGlib(&glib1_ver);
+	}
+}
+#endif
 
 /** NOTE: For a description of the rationale for this involved loading procedure rkapi.h ! */
+int main(int argc, char *argv[]) {
+// TODO: Take lib name from CMake?
 	if (argc > 10) {
 		fprintf(stderr, "Too many args\n"); // and I'm lazy
 		exit(99);
@@ -93,6 +123,8 @@ int main(int argc, char *argv[]) {
 		exit(99);
 	}
 
+	char* c_rk_ld_cwd = getenv("RK_LD_CWD");
+
 #if defined(Win32)
 	auto r_dllinfo = loadlib("R.dll");
 #elif defined(__APPLE__)
@@ -103,9 +135,9 @@ int main(int argc, char *argv[]) {
 	auto r_dllinfo = loadlib("libR.dylib");
 #else
 	auto r_dllinfo = loadlib("libR.so");
+	preloadBetterGlib(c_rk_ld_cwd);
 #endif
 
-	char* c_rk_ld_cwd = getenv("RK_LD_CWD");
 	auto cd = std::filesystem::current_path();
 	if (c_rk_ld_cwd && c_rk_ld_cwd[0]) {
 		std::filesystem::current_path(c_rk_ld_cwd);



More information about the rkward-tracker mailing list