Programmatically accessing autotools install paths

One of many problems that users of the useful-but-baroque GNU autotools framework may find themselves running into is that their program needs to load in files which got installed at the same time as the executable. But where are they? The installer allows data files to be placed godknowswhere using ./configure --prefix or ./configure --datarootdir or any number of other bizzare options unknown to me - hard-coded paths aren't going to work unless you go out of your way to subvert the actions of autotools. Bad idea.

So, you're going to have to use automake in ways not strictly intended and make template executable/library files on the fly as configure and make get run. I say "not strictly intended", because the way of doing this is so clunky that if they were intended, they were intended by someone with access to far too much crack. There's a couple of approaches.

Shell script generation First up, let's try the way that probably was intended - a shell script:

#! /usr/bin/env bash

# This variable needs to exist      prefix=@prefix@

if [[ $# -eq 0 || -n $( echo $* | egrep -- "--help|-h" ) ]]; then          echo "lhapdf-config: configuration tool

for the LHAPDF" echo " parton density function evolution library" echo "" echo echo "Usage: lhapdf-config [[--help|-h] | [--prefix] | [--pdfsets-path]]" echo "Options:" echo " --help | -h : show this help message" echo " --prefix : show the installation prefix (cf. autoconf)" echo " --datadir : show the path to the LHAPDF installed data directory" echo " --pdfsets-path : show the path to the directory containing the PDF set data files" echo fi

if [[ -n $( echo $* | egrep -- --prefix ) ]]; then          echo $prefix      fi

if [[ -n $( echo $* | egrep -- --datadir ) ]]; then          echo @datadir@/@PACKAGE_TARNAME@      fi

if [[ -n $( echo $* | egrep -- --pdfsets-path ) ]]; then          echo @datadir@/@PACKAGE_TARNAME@/PDFsets      fi

This script template should be given an extra .in filename extension and referenced as a Makefile template would be in your file. When configure is run, automake will replace the @foo@ bits of the script template with appropriate paths in a new file without the .in suffix. Great: now the generated script can be installed, and used in a Fortran/C++/whatever system call to write out the appropriate path.

All very well, but this now forces us to make system calls, assume things about shell capabilities and writeable filesystem locations... not ideal. If you do go down this road, I'd advise that you make the code that uses it write the output path into the user's home directory in a hidden dot-directory, otherwise you'll end up with different user denying each other write-permission to the path file, or you'll fill up your drive with identical temp files. Yuck.

Generated library routines

Well, we can do better than that, but now it obviously wasn't intended. Let's make a C++ library function as a template:

const string getInstalledDataPath() {        const string prefix = "@prefix@";        string datadir =

"@datadir@/@PACKAGE_TARNAME@"; datadir.replace(datadir.begin(), datadir.begin()+9, prefix); return datadir; }

Again, put it in a file with a .in suffix, probably something like, tell about it, add the generated .cc version of the file to your executable/library's source list and try building. It works, and since the .cc file gets rebuilt when you re-run configure with different options, re-running configure will also force make to rebuild this function. And we don't touch the filesystem, which is usually a good idea if you don't have to.

Note that the third line in the function body is a hack - @datadir@ by default expands to ${prefix}/share, so it's only designed to work in shell scripts. Personally, I think that's a bug, but autotools is all a bit crumby and I suspect I'd be told "don't do that" if I reported it! The third line replaces the first 9 characters (i.e. ${prefix}) with the value of the @prefix@ variable, which is actually a valid path. You'll notice that the shell script has to make sure that a variable called prefix exists for exactly this reason.

Job done. Makes your skin crawl, doesn't it?