Supporting Relocation
=====================

It has been a pain for many users of GNU packages for a long time that packages are not relocatable.  It means a user cannot copy a program, installed by another user on the same machine, to his home directory, and have it work correctly (including i18n).  So many users need to go through configure; make; make install with all its dependencies, options, and hurdles.

Red Hat, Debian, and similar package systems solve the ``ease of installation'' problem, but they hardwire path names, usually to /usr or /usr/local.  This means that users need root privileges to install a binary package, and prevents installing two different versions of the same binary package.

A relocatable program can be moved or copied to a different location on the filesystem.  It is possible to make symlinks to the installed and moved programs, and invoke them through the symlink. It is possible to do the same thing with a hard link only if the hard link file is in the same directory as the real program.

The relocatable module aims to ease the process of making a GNU program relocatable.  It helps overcome two obstacles.  First, it aids with relocating the hard-coded references to absolute file names that GNU programs often contain.  These references must be fixed up at runtime if a program is to be successfully relocated.  The relocatable module provides a function relocate that does this job.

Second, the loader must be able to find shared libraries linked to relocatable executables or referenced by other shared libraries linked to relocatable executables.  The relocatable module helps out here in a platform-specific way:

  * On GNU/Linux, it adds a linker option (-rpath) that causes the dynamic linker to search for libraries in a directory relative to the location of the invoked executable.

  * On other Unix systems, it installs a wrapper executable.  The wrapper sets the environment variable that controls shared library searching (usually LD_LIBRARY_PATH) and then invokes the real executable.

     This approach does not always work.  On OpenBSD and OpenServer, prereleases of Libtool 1.5 put absolute file names of libraries in executables, which prevents searching any other locations.

  * On Windows, the executable's own directory is searched for libraries, so installing shared libraries into the executable's directory is sufficient.

You can make your program relocatable by following these steps:

 1. Import the relocatable module.

 2. In every program, add to main as the first statement (even before setting the locale or doing anything related to libintl):

          set_program_name (argv[0]);

     The prototype for this function is in progname.h.

 3. Everywhere where you use a constant pathname from installation-time, wrap it in relocate so it gets translated to the run-time situation. Example:

          bindtextdomain (PACKAGE, LOCALEDIR);

     becomes:

          bindtextdomain (PACKAGE, relocate (LOCALEDIR));

     The prototype for this function is in relocatable.h.

 4. If your package installs shell scripts, also import the relocatable-script module.  Then, near the beginning of each shell script that your package installs, add the following:

          @relocatable_sh@
          if test "@RELOCATABLE@" = yes; then
            exec_prefix="@exec_prefix@"
            bindir="@bindir@"
            orig_installdir="$bindir" # see Makefile.am's *_SCRIPTS variables
            func_find_curr_installdir # determine curr_installdir
            func_find_prefixes
            # Relocate the directory variables that we use.
            gettext_dir=`echo "$gettext_dir/" | sed -e
          "s%^${orig_installprefix}/%${curr_installprefix}/%" | sed -e 's,/$,,'`
          fi

     You must adapt the definition of orig_installdir, depending on where the script gets installed.  Also, at the end, instead of gettext_dir, transform those variables that you need.

 5. In your Makefile.am, for every program foo that gets installed in, say, $(bindir), you add:

          foo_CPPFLAGS = -DINSTALLDIR=\"$(bindir)\"
          if RELOCATABLE_VIA_LD
          foo_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)`
          endif

 6. You may also need to add one or two variable assignments to your configure.ac.

     If your package (or any package you rely on, e.g. gettext-runtime) will be relocated together with a set of installed shared libraries, then set RELOCATABLE_LIBRARY_PATH to a colon-separated list of those libraries' directories, e.g.

          RELOCATABLE_LIBRARY_PATH='$(libdir)'

     If your config.h is not in $(top_builddir), then set RELOCATABLE_CONFIG_H_DIR to its directory, e.g.

          RELOCATABLE_CONFIG_H_DIR='$(top_builddir)/src'