logo Autopackage - Easy Linux Software Installation

Autopackage GNOME Launch Box Tutorial

Binary Relocatability

Autopackages can be installed to the users home directory (or to any other prefix), and this feature is popular with end users. Therefore, to build an autopackage, you must firstly ensure that your software can locate all its files at runtime without using hard coded paths. This isn't hard.

Firstly, decide how you will implement this feature. For C programs like Launch Box, there are two approaches: using the BinReloc pre-made kit, and simply doing it by hand. The BinReloc tool generates a C file that you can compile and link into your application: it reads /proc/self/exe (among other things) if available, and lets you determine your applications prefix from that. It'll fall back to the compile-time defaults if it fails. The other approach is to do the same thing, but manually. If your code already supports relocatability (for instance, because it's portable to Windows) then this may be easier.

Let's use the binreloc kit. First of all, we must locate where compiled in paths are being used. Looking at the Makefile.am in the src directory, we see the following code:

AM_CPPFLAGS = \
        -DIMAGEDIR=\"$(datadir)/lb/images\" \
        ......

Ah, the IMAGEDIR macro is being used somewhere. Grepping for it, we find it's used in the lb-window.c file:

switch (corner) {
case LB_WINDOW_CORNER_TOP_LEFT:
	filename = IMAGEDIR "/lb-top-left.png";
	break;
case LB_WINDOW_CORNER_TOP_RIGHT:
	filename = IMAGEDIR "/lb-top-right.png";
	break;

.... (and so on)

The first step is to make this code use dynamic (heap allocated) strings instead of statically allocated strings produced by the C preprocessor. This isn't too hard, because Launch Box is a glib app we can use the g_build_file_name call (remembering to add a g_free after the filename variable is used):

switch (corner) {
case LB_WINDOW_CORNER_TOP_LEFT:
	filename = g_build_filename (IMAGEDIR, "lb-top-left.png", NULL);
	break;
case LB_WINDOW_CORNER_TOP_RIGHT:
	filename = g_build_filename (IMAGEDIR, "lb-top-right.png", NULL);
	break;

.... (and so on)

Now we need to change the constant IMAGEDIR macro into a variable. The easiest way to do this is to generate a binreloc.[ch] pair for your program then use a constructor function, but you could also put this somewhere in your main function.

Grab binreloc from autopackage CVS, then run the generate.pl script. In this instance, we want the glib-ized version not the raw C version so pass "glib" as a parameter. It'll output two files: binreloc.c and binreloc.h. Add them to Makefile.am and re-run autogen, and now it's integrated with our project.

static gchar *imagedir;

/* will be called automatically before main() */
static void __attribute__((constructor))
locate_image_dir () 
{
        if (gbr_init (NULL))
	        imagedir = g_build_filename (gbr_find_data_dir (DATADIR), "lb", "images", NULL);
        else
	        imagedir = DATADIR "/lb/images";
}			

Now we just change "IMAGEDIR" to "imagedir" in the window_pixbuf_fill_corner function and we're done. Let's test it!

There is a very simple way to ensure you got binary relocatability correct: install your program to its own prefix, and run it. Then rename that prefix and run it again. Does it work correctly?

$ make install DESTDIR=/tmp/glb
$ /tmp/glb/usr/local/bin/gnome-launch-box
(no errors)
$ mv /tmp/glb /tmp/glb2
$ /tmp/glb2/usr/local/bin/gnome-launch-box
(no errors)

And we're done! You can read the full patch here.

See also the Guide to Making Relocatable Applications for full documentation about BinReloc.

Autopackage GNOME Launch Box Tutorial