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