[Gimp-developer] Patch: binary relocatability support for Gimp

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Win32, Gimp is relocatable. It can find out it's own path at runtime and find out where it's data files are. On Linux, all paths in Gimp are hardcoded at compile time. This means the app is not relocatable.

I work for the autopackage project (http://autopackage.org/), a new installation system for Linux. One of the features of autopackage is that packages can be installed to any prefix (although that's not recommended), which means the software must be relocatable. Because there's no real easy way to quickly find out the path of a library or application.
See also http://autopackage.org/docs/binreloc/ for more info about BinReloc and the relocation problem.


Anyway, to the point. I'm packaging Gimp 2 currently and I've modified Gimp to be relocatable on Linux. The patch is mostly finished but there are still minor issues to take care of. I'd like to know if this patch is good enough to be able to get accepted, and if not, why.

Please note that adding binary relocation support on Linux will not harm portability! I wrote a configure check for this, and binary relocation support will be automatically disabled if the system is not running on Linux. The user can also explicitly tell configure to disable binreloc support.

I am aware that app/main.c sets LD_LIBRARY_PATH. This is just temporary because it's less work than modifying every Makefile for every plugin. Apart from this obvious hack, how does the rest of the patch look? Is it good enough to be accepted once I remove the LD_LIBRARY_PATH hack?
--- gimp-2.0.0/app/main.c.old	2004-04-07 19:47:40.000000000 +0200
+++ gimp-2.0.0/app/main.c	2004-04-07 19:48:21.000000000 +0200
@@ -41,6 +41,7 @@
 #include <glib-object.h>
 
 #include "libgimpbase/gimpbase.h"
+#include "libgimpbase/prefix.h"
 
 #include "config/gimpconfig-dump.h"
 
@@ -114,6 +115,9 @@
   GimpPDBCompatMode   pdb_compat_mode         = GIMP_PDB_COMPAT_WARN;
 #endif
   gint                i, j;
+#ifdef ENABLE_BINRELOC
+  gchar              *libpath, *tmp;
+#endif
 
 #if 0
   g_mem_set_vtable (glib_mem_profiler_table);
@@ -140,6 +144,19 @@
 
   textdomain (GETTEXT_PACKAGE);
 
+#ifdef ENABLE_BINRELOC
+  tmp = gimp_br_prepend_prefix ("", "/lib");
+  libpath = (gchar *) g_getenv ("LD_LIBRARY_PATH");
+  if (libpath && *libpath)
+    {
+      libpath = g_strdup_printf ("%s:%s", tmp, libpath);
+      setenv ("LD_LIBRARY_PATH", libpath, 1);
+      g_free (tmp);
+    }
+  else
+    setenv ("LD_LIBRARY_PATH", tmp, 1);
+#endif
+
   /* Check argv[] for "--no-interface" before trying to initialize gtk+.
    * We also check for "--help" or "--version" here since those shouldn't
    * require gui libs either.
--- gimp-2.0.0/app/Makefile.am.old	2004-04-07 19:47:45.000000000 +0200
+++ gimp-2.0.0/app/Makefile.am	2004-04-07 19:48:21.000000000 +0200
@@ -64,7 +64,8 @@
 	-DG_LOG_DOMAIN=\"Gimp\"		\
 	-DGIMP_APP_GLUE_COMPILATION	\
 	@GIMP_THREAD_FLAGS@ 		\
-	@GIMP_MP_FLAGS@
+	@GIMP_MP_FLAGS@			\
+	$(BINRELOC_CFLAGS)
 
 INCLUDES = \
 	-I$(top_srcdir)	\
--- gimp-2.0.0/libgimpbase/gimpenv.c.old	2004-04-07 19:47:54.000000000 +0200
+++ gimp-2.0.0/libgimpbase/gimpenv.c	2004-04-07 19:48:21.000000000 +0200
@@ -31,6 +31,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#include <prefix.h>
+
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
--- gimp-2.0.0/libgimpbase/Makefile.am.old	2004-04-07 19:47:57.000000000 +0200
+++ gimp-2.0.0/libgimpbase/Makefile.am	2004-04-07 19:48:21.000000000 +0200
@@ -47,6 +47,10 @@
 	-DPLUGINDIR=\""$(gimpplugindir)"\"	\
 	-DSYSCONFDIR=\""$(gimpsysconfdir)"\"	\
 	-DG_LOG_DOMAIN=\"LibGimpBase\"		\
+	-DGIMP_DATA_VERSION=\"$(GIMP_DATA_VERSION)\"		\
+	-DGIMP_SYSCONF_VERSION=\"$(GIMP_SYSCONF_VERSION)\"	\
+	-DGIMP_PLUGIN_VERSION=\"$(GIMP_PLUGIN_VERSION)\"	\
+	$(BINRELOC_CFLAGS)			\
 	@GIMP_THREAD_FLAGS@
 
 INCLUDES = \
@@ -91,7 +95,9 @@
 	gimputils.h            	\
 	gimpwin32-io.h		\
 	gimpwire.c		\
-	gimpwire.h
+	gimpwire.h		\
+	prefix.c		\
+	prefix.h
 
 libgimpbaseinclude_HEADERS = \
 	gimpbase.h		\
--- gimp-2.0.0/configure.in.old	2004-04-07 19:48:16.000000000 +0200
+++ gimp-2.0.0/configure.in	2004-04-07 20:11:27.000000000 +0200
@@ -376,6 +376,59 @@
 AC_CHECK_FUNCS(difftime putenv mmap)
 
 
+AC_ARG_ENABLE(binreloc,
+	[  --enable-binreloc       compile with binary relocation support
+                          (default=enable when available)],
+	enable_binreloc=$enableval,enable_binreloc=auto)
+BINRELOC_CFLAGS=
+
+AC_MSG_CHECKING(whether binary relocation support should be enabled)
+if test "$enable_binreloc" = "yes"; then
+	AC_MSG_RESULT(yes)
+	AC_MSG_CHECKING(for linker mappings at /proc/self/maps)
+	if test -e /proc/self/maps; then
+		AC_MSG_RESULT(yes)
+		BINRELOC_CFLAGS=-DENABLE_BINRELOC
+	else
+		AC_MSG_RESULT(no)
+		AC_MSG_ERROR(/proc/self/maps is not available. Binary relocation cannot be enabled.)
+	fi
+
+elif test "$enable_binreloc" = "auto"; then
+	AC_MSG_RESULT(yes when available)
+	AC_MSG_CHECKING(for linker mappings at /proc/self/maps)
+	if test -e /proc/self/maps; then
+		AC_MSG_RESULT(yes)
+		enable_binreloc=yes
+		
+		AC_MSG_CHECKING(whether everything is installed to the same prefix)
+		if test "$bindir" = '${exec_prefix}/bin' -a "$sbindir" = '${exec_prefix}/sbin' -a \
+			"$datadir" = '${prefix}/share' -a "$libdir" = '${exec_prefix}/lib' -a \
+			"$libexecdir" = '${exec_prefix}/libexec' -a "$sysconfdir" = '${prefix}/etc'
+		then
+			BINRELOC_CFLAGS=-DENABLE_BINRELOC
+			AC_MSG_RESULT(yes)
+		else
+			AC_MSG_RESULT(no)
+			AC_MSG_NOTICE(Binary relocation support will be disabled.)
+			enable_binreloc=no
+		fi
+
+	else
+		AC_MSG_RESULT(no)
+		enable_binreloc=no
+	fi
+
+elif test "$enable_binreloc" = "no"; then
+	AC_MSG_RESULT(no)
+else
+	AC_MSG_RESULT(no (unknown value "$enable_binreloc"))
+	enable_binreloc=no
+fi
+
+AC_SUBST(BINRELOC_CFLAGS)
+
+
 ######################
 # Internationalisation
 ######################
--- /dev/null	2003-09-15 15:40:47.000000000 +0200
+++ gimp-2.0.0/libgimpbase/prefix.c	2004-04-07 19:48:21.000000000 +0200
@@ -0,0 +1,315 @@
+/*
+ * BinReloc - a library for creating relocatable executables
+ * Written by: Mike Hearn <mike@xxxxxxxxxxxxx>
+ *             Hongli Lai <h.lai@xxxxxxxxx>
+ * http://autopackage.org/
+ * 
+ * This source code is public domain. You can relicense this code
+ * under whatever license you want.
+ */
+
+/* Modified for use in The GIMP */
+
+#ifndef _PREFIX_C_
+#define _PREFIX_C_
+
+#define __USE_GNU
+#include <features.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include "prefix.h"
+
+#undef NULL
+#define NULL ((void *) 0)
+
+#ifdef __GNUC__
+	#define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;}
+#else
+	#define br_return_val_if_fail(expr,val) if (!(expr)) return val
+#endif /* __GNUC__ */
+
+
+#ifdef ENABLE_BINRELOC
+#define __USE_GNU
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+
+/**
+ * br_locate:
+ * symbol: A symbol that belongs to the app/library you want to locate.
+ * Returns: A newly allocated string containing the full path of the
+ *	    app/library that func belongs to, or NULL on error. This
+ *	    string should be freed when not when no longer needed.
+ *
+ * Finds out to which application or library symbol belongs, then locate
+ * the full path of that application or library.
+ * Note that symbol cannot be a pointer to a function. That will not work.
+ *
+ * Example:
+ * // main.c
+ * #include "prefix.h"
+ * #include "libfoo.h"
+ *
+ * int main (int argc, char *argv[]) {
+ *	printf ("Full path of this app: %s\n", br_locate (&argc));
+ *	libfoo_start ();
+ *	return 0;
+ * }
+ *
+ * // libfoo.c starts here
+ * #include "prefix.h"
+ *
+ * void libfoo_start () {
+ *	// "" is a symbol that belongs to libfoo (because it's called
+ *	// from libfoo_start()); that's why this works.
+ *	printf ("libfoo is located in: %s\n", br_locate (""));
+ * }
+ */
+char *
+gimp_br_locate (void *symbol)
+{
+	char line[5000];
+	FILE *f;
+	char *path;
+
+	br_return_val_if_fail (symbol != NULL, NULL);
+
+	f = fopen ("/proc/self/maps", "r");
+	if (!f)
+		return NULL;
+
+	while (!feof (f))
+	{
+		unsigned int start, end;
+
+		if (!fgets (line, sizeof (line), f))
+			continue;
+		if (!strstr (line, " r-xp ") || !strchr (line, '/'))
+			continue;
+
+		sscanf (line, "%x-%x ", &start, &end);
+		if (((unsigned int) symbol) >= start && ((unsigned int) symbol) < end)
+		{
+			char *tmp;
+			size_t len;
+
+			/* Extract the filename; it is always an absolute path */
+			path = strchr (line, '/');
+
+			/* Get rid of the newline */
+			tmp = strrchr (path, '\n');
+			if (tmp) *tmp = 0;
+
+			/* Get rid of "(deleted)" */
+			len = strlen (path);
+			if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0)
+			{
+				tmp = path + len - 10;
+				*tmp = 0;
+			}
+
+			fclose(f);
+			return strdup (path);
+		}
+	}
+
+	fclose (f);
+	return NULL;
+}
+
+
+/**
+ * br_locate_prefix:
+ * symbol: A symbol that belongs to the app/library you want to locate.
+ * Returns: A prefix. This string should be freed when no longer needed.
+ *
+ * Locates the full path of the app/library that symbol belongs to, and return
+ * the prefix of that path, or NULL on error.
+ * Note that symbol cannot be a pointer to a function. That will not work.
+ *
+ * Example:
+ * // This application is located in /usr/bin/foo
+ * br_locate_prefix (&argc);   // returns: "/usr"
+ */
+char *
+gimp_br_locate_prefix (void *symbol)
+{
+	char *path, *prefix;
+
+	br_return_val_if_fail (symbol != NULL, NULL);
+
+	path = gimp_br_locate (symbol);
+	if (!path) return NULL;
+
+	prefix = gimp_br_extract_prefix (path);
+	free (path);
+	return prefix;
+}
+
+
+/**
+ * br_prepend_prefix:
+ * symbol: A symbol that belongs to the app/library you want to locate.
+ * path: The path that you want to prepend the prefix to.
+ * Returns: The new path, or NULL on error. This string should be freed when no
+ *	    longer needed.
+ *
+ * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path.
+ * Note that symbol cannot be a pointer to a function. That will not work.
+ *
+ * Example:
+ * // The application is /usr/bin/foo
+ * br_prepend_prefix (&argc, "/share/foo/data.png");   // Returns "/usr/share/foo/data.png"
+ */
+char *
+gimp_br_prepend_prefix (void *symbol, char *path)
+{
+	char *tmp, *newpath;
+
+	br_return_val_if_fail (symbol != NULL, NULL);
+	br_return_val_if_fail (path != NULL, NULL);
+
+	tmp = gimp_br_locate_prefix (symbol);
+	if (!tmp) return NULL;
+
+	if (strcmp (tmp, "/") == 0)
+		newpath = strdup (path);
+	else
+		newpath = gimp_br_strcat (tmp, path);
+
+	/* Get rid of compiler warning ("br_prepend_prefix never used") */
+	if (0) gimp_br_prepend_prefix (NULL, NULL);
+
+	free (tmp);
+	return newpath;
+}
+
+
+/**
+ * br_strcat:
+ * str1: A string.
+ * str2: Another string.
+ * Returns: A newly-allocated string. This string should be freed when no longer needed.
+ *
+ * Concatenate str1 and str2 to a newly allocated string.
+ */
+char *
+gimp_br_strcat (const char *str1, const char *str2)
+{
+	char *result;
+
+	if (!str1) str1 = "";
+	if (!str2) str2 = "";
+
+	result = calloc (sizeof (char), strlen (str1) + strlen (str2) + 1);
+	result = strcpy (result, str1);
+	result = strcat (result, str2);
+	return result;
+}
+
+
+/* Emulates glibc's strndup() */
+static char *
+br_strndup (char *str, size_t size)
+{
+	char *result = NULL;
+	size_t len;
+
+	br_return_val_if_fail (str != NULL, NULL);
+
+	len = strlen (str);
+	if (!len) return strdup ("");
+
+	result = calloc (sizeof (char), len + 1);
+	memcpy (result, str, size);
+	return result;
+}
+
+
+/**
+ * br_extract_dir:
+ * path: A path.
+ * Returns: A directory name. This string should be freed when no longer needed.
+ *
+ * Extracts the directory component of path. Similar to g_dirname() or the dirname
+ * commandline application.
+ *
+ * Example:
+ * br_extract_dir ("/usr/local/foobar");  // Returns: "/usr/local"
+ */
+char *
+gimp_br_extract_dir (const char *path)
+{
+	char *end, *result;
+
+	br_return_val_if_fail (path != NULL, NULL);
+
+	end = strrchr (path, '/');
+	if (!end) return strdup (".");
+
+	while (end > path && *end == '/')
+		end--;
+	result = br_strndup ((char *) path, end - path + 1);
+	if (!*result)
+	{
+		free (result);
+		return strdup ("/");
+	} else
+		return result;
+}
+
+
+/**
+ * br_extract_prefix:
+ * path: The full path of an executable or library.
+ * Returns: The prefix, or NULL on error. This string should be freed when no longer needed.
+ *
+ * Extracts the prefix from path. This function assumes that your executable
+ * or library is installed in an LSB-compatible directory structure.
+ *
+ * Example:
+ * br_extract_prefix ("/usr/bin/gnome-panel");   // Returns "/usr"
+ * br_extract_prefix ("/usr/local/libfoo.so");   // Returns "/usr/local"
+ */
+char *
+gimp_br_extract_prefix (const char *path)
+{
+	char *end, *tmp, *result;
+
+	br_return_val_if_fail (path != NULL, NULL);
+
+	if (!*path) return strdup ("/");
+	end = strrchr (path, '/');
+	if (!end) return strdup (path);
+
+	tmp = br_strndup ((char *) path, end - path);
+	if (!*tmp)
+	{
+		free (tmp);
+		return strdup ("/");
+	}
+	end = strrchr (tmp, '/');
+	if (!end) return tmp;
+
+	result = br_strndup (tmp, end - tmp);
+	free (tmp);
+
+	if (!*result)
+	{
+		free (result);
+		result = strdup ("/");
+	}
+
+	return result;
+}
+
+
+#endif /* ENABLE_BINRELOC */
+
+#endif /* _PREFIX_C */
--- /dev/null	2003-09-15 15:40:47.000000000 +0200
+++ gimp-2.0.0/libgimpbase/prefix.h	2004-04-07 19:48:21.000000000 +0200
@@ -0,0 +1,42 @@
+/*
+ * BinReloc - a library for creating relocatable executables
+ * Written by: Mike Hearn <mike@xxxxxxxxxxxxx>
+ *             Hongli Lai <h.lai@xxxxxxxxx>
+ * http://autopackage.org/
+ *
+ * This source code is public domain. You can relicense this code
+ * under whatever license you want.
+ *
+ * See README and USAGE in the original source distribution for
+ * more information and how to use this.
+ */
+
+/* Modified for use in The GIMP */
+
+#ifndef _PREFIX_H_
+#define _PREFIX_H_
+
+#ifdef ENABLE_BINRELOC
+
+#undef DATADIR
+#define DATADIR gimp_br_prepend_prefix ("", "/share/gimp/" GIMP_DATA_VERSION)
+#undef LOCALEDIR
+#define LOCALEDIR gimp_br_prepend_prefix ("", "/share/locale")
+#undef SYSCONFDIR
+#define SYSCONFDIR gimp_br_prepend_prefix ("", "/etc/gimp/" GIMP_SYSCONF_VERSION)
+#undef PLUGINDIR
+#define PLUGINDIR gimp_br_prepend_prefix ("", "/lib/gimp/" GIMP_PLUGIN_VERSION)
+
+
+char *gimp_br_locate (void *symbol);
+char *gimp_br_locate_prefix (void *symbol);
+char *gimp_br_prepend_prefix (void *symbol, char *path);
+
+char *gimp_br_strcat (const char *str1, const char *str2);
+char *gimp_br_extract_dir (const char *path);
+char *gimp_br_extract_prefix (const char *path);
+
+
+#endif /* ENABLE_BINRELOC */
+
+#endif /* _PREFIX_H_ */

[Index of Archives]     [Video For Linux]     [Photo]     [Yosemite News]     [gtk]     [GIMP for Windows]     [KDE]     [GEGL]     [Gimp's Home]     [Gimp on GUI]     [Gimp on Windows]     [Steve's Art]

  Powered by Linux