Producing relocatable packages with the GNU build system


I’ve recently found a need to create relocatable versions of some of my favorite libraries (produced, not-so-coincidentally by the GNU build system). You might find yourself asking “What is relocatable software, and why should I care?” Maybe I can help.

A piece of software is said to be “relocatable” when it does not rely on an absolute path in a filesystem in order to operate correctly. An example of this type of system is OS X’s .app directory/package framework.

As it currently stands, if I were to install iceweasel (or Firefox™) in /usr/local/mozilla/, but later realize there is more disk space available in /opt, I would be SOL. If mozilla were built as a relocatable package, however, moving /usr/local/mozilla/ to /opt/mozilla/ would not be a problem.

There are a couple of things standing in the way of this shiny new future.

1) In its current state, GNU autoconf accepts multiple absolute paths as argument values. In a relocatable package, all related software must be installed relative to a single point, referred to in autoconf nomenclature as the “prefix”. In a perfect world, all directories relative to the prefix would be further constrained as not to be beneath the prefix root. For example, defining the “bindir” as ${prefix}/../bin/ would be a no-no.

I have proposed a solution to this problem on the bug-autoconf list.

2) After a package is created in a relocatable way, how does one find said package once it has been moved?

The solution to this problem lies in the standardization of the use of pkg-config and subsequent modifications to the $PKG_CONFIG_PATH environment variable.

The first step is to ensure that your GNU build system includes a rule to generate a .pc file. The standard way to do this is to include a .pc.in autoconf template in the distribution as well as an entry in the AC_OUTPUT( … ) macro of the configure.am file (configure.in in legacy codebases).

Here are some examples from the Mono codebase. Note that configure.am is named configure.in in the mono codebase. Note further that I am scowling.

AC_OUTPUT([
Makefile
mint.pc
mono.pc
mono-cairo.pc
dotnet.pc
mono-uninstalled.pc
scripts/mono-nunit.pc
...
])

Here are a couple of examples of the contents of .pc.in files:

cjac@dom0:/usr/src/svn/mono/mono-1.2.5$ cat mint.pc.in 
prefix=${pcfiledir}/../..
exec_prefix=${pcfiledir}/../..
libdir=${prefix}/lib
includedir=${prefix}/include/mono-@API_VER@


Name: Mono Interpreter
Description: Mono Interpreter Runtime
Version: @VERSION@
Requires: glib-2.0 gthread-2.0
Libs: -L${libdir} @export_ldflags@ -lmint @libmono_ldflags@
Cflags: -I${includedir} @libmono_cflags@

cjac@dom0:/usr/src/svn/mono/mono-1.2.5$ cat mono.pc.in 
prefix=${pcfiledir}/../..
exec_prefix=${pcfiledir}/../..
libdir=${prefix}/@reloc_libdir@
includedir=${prefix}/include/mono-@API_VER@

Name: Mono
Description: Mono Runtime
Version: @VERSION@
Requires: glib-2.0 gthread-2.0
Libs: -L${libdir} @export_ldflags@ -lmono @libmono_ldflags@
Cflags: -I${includedir} @libmono_cflags@

Of particular importance in these files is the definition of ${prefix}, ${exec_prefix}, ${libdir} and ${includedir} relative to ${pcfiledir}. ${pcfiledir} is set at pkg-config run time as it iterates over the contents of the $PKG_CONFIG_PATH environment variable.

For example, if $PKG_CONFIG_PATH evaluates as “/home/cjac/opt/mono/lib/pkgconfig:/usr/lib/pkgconfig”, on the first iteration, ${pcfiledir} will store /home/cjac/opt/mono/lib/pkgconfig, and on the second iteration, ${pcfiledir} will store /usr/lib/pkgconfig.

So! Assuming I installed mono to ~/opt/mono, and I wanted to instead move it to /opt/mono, all I would need to do is the following:

$ sudo mv ~/opt/mono /opt
$ export PKG_CONFIG_PATH="/opt/mono/lib/pkgconfig:$PKG_CONFIG_PATH"

And voila. All of my mono-related bits and all references to them have been moved. Independent of the absolute path to the mono package, the prefix can be determined in a consistent way:

$ pkg-config mono --variable=prefix

Comment away… I’ll try to get rid of some of the spam crowding my comment backlog…


Leave a Reply