@node Supporting Relocation @section 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 @code{configure; make; make install} with all its dependencies, options, and hurdles. Red Hat, Debian, and other binary distributions solve the ``ease of installation'' problem, but they hardwire path names, usually to @file{/usr} or @file{/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 file system. 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 @emph{only} if the hard link file is in the same directory as the real program. The @code{relocatable-prog} 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 @code{relocatable-prog} module provides a function @code{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 @code{relocatable-prog} module helps out here in a platform-specific way: @itemize @item On most operating systems, it adds a linker option (@option{-rpath}) that causes the dynamic linker to search for libraries in a directory relative to the location of the invoked executable. This works on GNU/Linux and modern versions of GNU/Hurd, GNU/kFreeBSD, macOS, FreeBSD, NetBSD, OpenBSD, Solaris, Haiku. @item On other Unix systems, it installs a trampoline executable. The trampoline sets the environment variable that controls shared library searching (usually @env{LD_LIBRARY_PATH}) and then invokes the real executable. This applies to operating systems such as AIX, HP-UX, or Minix. @item On Windows, the executable's own directory is searched for libraries, so installing shared libraries into the executable's directory is sufficient. @end itemize You can make your program relocatable by following these steps: @enumerate @item Import the @code{relocatable-prog} module. For libraries, use the @code{relocatable-lib} or @code{relocatable-lib-lgpl} module, if the libraries are independent. For installing multiple libraries, at least one of which depends on another one, use the @code{relocatable-prog} module. If you need more than one module, or you need to use them with different settings, you will need multiple copies of gnulib (@pxref{Multiple instances}). @item In every program, add to @code{main} as the first statement (even before setting the locale or doing anything related to libintl): @example set_program_name (argv[0]); @end example The prototype for this function is in @file{progname.h}. @item If you want your code to be portable to platforms that do not support automatic initialization, call @code{set_relocation_prefix}. @item Everywhere where you use a constant pathname from installation-time, wrap it in @code{relocate} so it gets translated to the run-time situation. Example: @example bindtextdomain (PACKAGE, LOCALEDIR); @end example @noindent becomes: @example bindtextdomain (PACKAGE, relocate (LOCALEDIR)); @end example The prototype for this function is in @file{relocatable.h}. There is also a variant of this function, named @code{relocate2}, that makes it easy to reclaim the memory allocated by the call. @item The @code{set_program_name} function can also configure some additional libraries to relocate files that they access, by defining corresponding C preprocessor symbols to 1. The libraries for which this is supported and the corresponding preprocessor symbols are: @table @asis @item libcharset @code{DEPENDS_ON_LIBCHARSET} @item libiconv @code{DEPENDS_ON_LIBICONV} @item libintl @code{DEPENDS_ON_LIBINTL} @end table Defining the symbol for a library makes every program in the package depend on that library, whether the program really uses the library or not, so this feature should be used with some caution. @item If your package installs shell scripts, also import the @code{relocatable-script} module. Then, near the beginning of each shell script that your package installs, add the following: @smallexample @@relocatable_sh@@ prefix="@@prefix@@" exec_prefix="@@exec_prefix@@" # usually needs $prefix. datarootdir="@@datarootdir@@" # usually needs $prefix. if test "@@RELOCATABLE@@" = yes; then bindir="@@bindir@@" orig_installdir="$bindir" # see Makefile.am's *_SCRIPTS variables func_find_curr_installdir # determine curr_installdir func_find_prefixes relocate () @{ echo "$1/" \ | sed -e "s%^$@{orig_installprefix@}/%$@{curr_installprefix@}/%" \ | sed -e 's,/$,,' @} else relocate () @{ echo "$1" @} fi # Get some relocated directory names. sysconfdir=`relocate "@@sysconfdir@@"` # usually needs $prefix. some_datadir=`relocate "@@datadir@@/something"` # usually needs $datarootdir. bindir=`relocate "@@bindir@@"` # usually needs $exec_prefix, hence $prefix. @end smallexample You must adapt the definition of @code{orig_installdir}, depending on where the script gets installed. Also, at the end, instead of @code{sysconfdir} and @code{some_datadir}, transform those variables that you need. @item If your package installs Perl scripts, also import the @code{relocatable-perl} module. Then, near the beginning of each Perl script that your package installs, add the following: @smallexample @@relocatable_pl@@ if ("@@RELOCATABLE@@" eq "yes") @{ my $exec_prefix = "@@exec_prefix@@"; my $orig_installdir = "@@bindir@@"; # see Makefile.am's *_SCRIPTS variables my ($orig_installprefix, $curr_installprefix) = find_prefixes($orig_installdir, find_curr_installdir()); # the subroutine is defined whether or not the enclosing block is executed sub relocate @{ my ($dir) = @@_; if ("@@RELOCATABLE@@" eq "yes") @{ $dir =~ s%^$orig_installprefix/%$curr_installprefix/%; $dir =~ s,/$,,; @} return $dir; @} @} # Get some relocated directory names. # (The gnulib module 'configmake' can help with this.) $sysconfdir = relocate("@@sysconfdir@@"); $some_datadir = relocate(@@datadir@@/something"); @end smallexample You must adapt the definition of @code{$orig_installdir}, depending on where the script gets installed. Also, at the end, instead of @code{sysconfdir} and @code{some_datadir}, transform those variables that you need. @item In your @file{Makefile.am}, for every program @command{foo} that gets installed in, say, @file{$(bindir)}, you add: @example foo_CPPFLAGS = -DINSTALLDIR=\"$(bindir)\" if RELOCATABLE_VIA_LD foo_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(bindir)` endif @end example When building gnulib to use with a relocatable library, you need to define the preprocessor symbol @code{IN_LIBRARY}. You may also want to build with @code{ENABLE_COSTLY_RELOCATABLE}, in which case you will also need to define @code{INSTALLDIR}. The following fragment can be added to an override @code{Makefile.am} used to build gnulib (@pxref{Modified build rules}). @example AM_CPPFLAGS += -DIN_LIBRARY -DENABLE_COSTLY_RELOCATABLE if SHLIBS_IN_BINDIR AM_CPPFLAGS += -DINSTALLDIR=\"$(bindir)\" else AM_CPPFLAGS += -DINSTALLDIR=\"$(libdir)\" endif @end example @code{SHLIBS_IN_BINDIR} is defined in @file{configure.ac} as follows: @smallexample AM_CONDITIONAL([SHLIBS_IN_BINDIR], [case "$host_os" in mingw* | cygwin*) true;; *) false;; esac]) @end smallexample @item In your @file{Makefile.am}, for every library @command{libfoo} that gets installed in, say, @file{$(libdir)}, you add: @example if RELOCATABLE_VIA_LD libfoo_la_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(libdir)` endif @end example @item Add a couple of variable assignments to your @file{Makefile.am}. 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 @code{RELOCATABLE_LIBRARY_PATH} to a colon-separated list of those libraries' directories, e.g. @example RELOCATABLE_LIBRARY_PATH = $(libdir) @end example If your @file{config.h} is not in @file{$(top_builddir)}, then set @code{RELOCATABLE_CONFIG_H_DIR} to its directory, e.g. @example RELOCATABLE_CONFIG_H_DIR = $(top_builddir)/src @end example @end enumerate