automake: Hard-Coded Install Paths

1 
1 27.10 Installing to Hard-Coded Locations
1 ========================================
1 
1      My package needs to install some configuration file.  I tried to use
1      the following rule, but ‘make distcheck’ fails.  Why?
1 
1           # Do not do this.
1           install-data-local:
1                   $(INSTALL_DATA) $(srcdir)/afile $(DESTDIR)/etc/afile
1 
1      My package needs to populate the installation directory of another
1      package at install-time.  I can easily compute that installation
1      directory in ‘configure’, but if I install files therein,
1      ‘make distcheck’ fails.  How else should I do?
1 
1    These two setups share their symptoms: ‘make distcheck’ fails because
1 they are installing files to hard-coded paths.  In the later case the
1 path is not really hard-coded in the package, but we can consider it to
1 be hard-coded in the system (or in whichever tool that supplies the
1 path).  As long as the path does not use any of the standard directory
1 variables (‘$(prefix)’, ‘$(bindir)’, ‘$(datadir)’, etc.), the effect
1 will be the same: user-installations are impossible.
1 
1    As a (non-root) user who wants to install a package, you usually have
1 no right to install anything in ‘/usr’ or ‘/usr/local’.  So you do
1 something like ‘./configure --prefix ~/usr’ to install a package in your
1 own ‘~/usr’ tree.
1 
1    If a package attempts to install something to some hard-coded path
1 (e.g., ‘/etc/afile’), regardless of this ‘--prefix’ setting, then the
1 installation will fail.  ‘make distcheck’ performs such a ‘--prefix’
1 installation, hence it will fail too.
1 
1    Now, there are some easy solutions.
1 
1    The above ‘install-data-local’ example for installing ‘/etc/afile’
1 would be better replaced by
1 
1      sysconf_DATA = afile
1 
1 by default ‘sysconfdir’ will be ‘$(prefix)/etc’, because this is what
1 the GNU Standards require.  When such a package is installed on an FHS
1 compliant system, the installer will have to set ‘--sysconfdir=/etc’.
1 As the maintainer of the package you should not be concerned by such
1 site policies: use the appropriate standard directory variable to
1 install your files so that the installer can easily redefine these
1 variables to match their site conventions.
1 
1    Installing files that should be used by another package is slightly
1 more involved.  Let’s take an example and assume you want to install a
1 shared library that is a Python extension module.  If you ask Python
1 where to install the library, it will answer something like this:
1 
1      % python -c 'from distutils import sysconfig;
1                   print sysconfig.get_python_lib(1,0)'
1      /usr/lib/python2.5/site-packages
1 
1    If you indeed use this absolute path to install your shared library,
1 non-root users will not be able to install the package, hence distcheck
1 fails.
1 
1    Let’s do better.  The ‘sysconfig.get_python_lib()’ function actually
1 accepts a third argument that will replace Python’s installation prefix.
1 
1      % python -c 'from distutils import sysconfig;
1                   print sysconfig.get_python_lib(1,0,"${exec_prefix}")'
1      ${exec_prefix}/lib/python2.5/site-packages
1 
1    You can also use this new path.  If you do
1    • root users can install your package with the same ‘--prefix’ as
1      Python (you get the behavior of the previous attempt)
1 
1    • non-root users can install your package too, they will have the
1      extension module in a place that is not searched by Python but they
1      can work around this using environment variables (and if you
1      installed scripts that use this shared library, it’s easy to tell
1      Python were to look in the beginning of your script, so the script
1      works in both cases).
1 
1    The ‘AM_PATH_PYTHON’ macro uses similar commands to define
1 ‘$(pythondir)’ and ‘$(pyexecdir)’ (⇒Python).
1 
1    Of course not all tools are as advanced as Python regarding that
1 substitution of PREFIX.  So another strategy is to figure the part of
1 the installation directory that must be preserved.  For instance, here
1 is how ‘AM_PATH_LISPDIR’ (⇒Emacs Lisp) computes ‘$(lispdir)’:
1 
1      $EMACS -batch -Q -eval '(while load-path
1        (princ (concat (car load-path) "\n"))
1        (setq load-path (cdr load-path)))' >conftest.out
1      lispdir=`sed -n
1        -e 's,/$,,'
1        -e '/.*\/lib\/x*emacs\/site-lisp$/{
1              s,.*/lib/\(x*emacs/site-lisp\)$,${libdir}/\1,;p;q;
1            }'
1        -e '/.*\/share\/x*emacs\/site-lisp$/{
1              s,.*/share/\(x*emacs/site-lisp\),${datarootdir}/\1,;p;q;
1            }'
1        conftest.out`
1 
1    I.e., it just picks the first directory that looks like
1 ‘*/lib/*emacs/site-lisp’ or ‘*/share/*emacs/site-lisp’ in the search
1 path of emacs, and then substitutes ‘${libdir}’ or ‘${datadir}’
1 appropriately.
1 
1    The emacs case looks complicated because it processes a list and
1 expects two possible layouts, otherwise it’s easy, and the benefits for
1 non-root users are really worth the extra ‘sed’ invocation.
1