[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
One of the more difficult problems with GNU Autotools driven projects is that each of them depends on ‘config.h’ (or its equivalent) and the project specific symbols that it defines. The purpose of this file is to be
#include
d from all of the project source files. The preprocessor can tailor then the code in these files to the target environment.It is often difficult and sometimes impossible to not introduce a dependency on ‘config.h’ from one of the project’s installable header files. It would be nice if you could simply install the generated ‘config.h’, but even if you name it carefully or install it to a subdirectory to avoid filename problems, the macros it defines will clash with those from any other GNU Autotools based project which also installs its ‘config.h’.
For example, if Sic installed its ‘config.h’ as ‘/usr/include/sic/config.h’, and had ‘#include <sic/config.h>’ in the installed ‘common.h’, when another GNU Autotools based project came to use the Sic library it might begin like this:
#if HAVE_CONFIG_H # include <config.h> #endif #if HAVE_SIC_H # include <sic.h> #endif static const char version_number[] = VERSION;But, ‘sic.h’ says ‘#include <sic/common.h>’, which in turn says ‘#include <sic/config.h>’. Even though the other project has the correct value for ‘VERSION’ in its own ‘config.h’, by the time the preprocessor reaches the ‘version_number’ definition, it has been redefined to the value in ‘sic/config.h’. Imagine the mess you could get into if you were using several libraries which each installed their own ‘config.h’ definitions. GCC issues a warning when a macro is redefined to a different value which would help you to catch this error. Some compilers do not issue a warning, and perhaps worse, other compilers will warn even if the repeated definitions have the same value, flooding you with hundreds of warnings for each source file that reads multiple ‘config.h’ headers.
The Autoconf macro
AC_OUTPUT_COMMANDS
(25) provides a way to solve this problem. The idea is to generate a system specific but installable header from the results of the various tests performed byconfigure
. There is a 1-to-1 mapping between the preprocessor code that relied on the configure results written to ‘config.h’, and the new shell code that relies on the configure results saved in ‘config.cache’.
The following code is a snippet from ‘configure.in’, in the body of
the AC_OUTPUT_COMMANDS
macro:
Compare this with the equivalent C pre-processor code from ‘sic/common.h’, which it replaces:
#if STDC_HEADERS || HAVE_STDLIB_H # include <stdlib.h> #endif #if HAVE_UNISTD_H # include <unistd.h> #endif #if HAVE_SYS_WAIT_H # include <sys/wait.h> #endif #if HAVE_ERRNO_H # include <errno.h> #endif #ifndef errno /* Some systems #define this! */ extern int errno; #endif #if HAVE_STRING_H # include <string.h> #else # if HAVE_STRING_H # include <strings.h> # endif #endif #if HAVE_ASSERT_H # include <assert.h> # define SIC_ASSERT assert #else # define SIC_ASSERT(expr) ((void) 0) #endif |
Apart from the mechanical process of translating the preprocessor code, there is some plumbing needed to ensure that the ‘common.h’ file generated by the new code in ‘configure.in’ is functionally equivalent to the old code, and is generated in a correct and timely fashion.
Taking my lead from some of the Automake generated make
rules
to regenerate ‘Makefile’ from ‘Makefile.in’ by calling
‘config.status’, I have added some similar rules to
‘sic/Makefile.am’ to regenerate ‘common.h’ from
‘common-h.in’.
The way that AC_OUTPUT_COMMANDS
works, is to copy the contained
code into config.status
(see section Generated File Dependencies). It is actually config.status
that creates the
generated files – for example, automake
generated
‘Makefile’s are able to regenerate themselves from corresponding
‘Makefile.in’s by calling config.status
if they become
out of date. Unfortunately, this means that config.status
doesn’t have direct access to the cache values generated while
configure
was running (because it has finished its work by the
time config.status
is called). It is tempting to read in the
cache file at the top of the code inside AC_OUTPUT_COMMANDS
, but
that only works if you know where the cache file is saved. Also the
package installer can use the ‘--cache-file’ option of
configure
to change the location of the file, or turn off
caching entirely with ‘--cache-file=/dev/null’.
AC_OUTPUT_COMMANDS
accepts a second argument which can be used
to pass the variable settings discovered by configure
into
config.status
. It’s not pretty, and is a little error prone.
In the first argument to AC_OUTPUT_COMMANDS
, you must be careful
to check that every single configure variable referenced is
correctly set somewhere in the second argument.
A slightly stripped down example from the sic project ‘configure.in’ looks like this:
You will notice that the contents of ‘common-h.in’ are copied into ‘common.h’ verbatim as it is generated. It’s just an easy way of collecting together the code that belongs in ‘common.h’, but which doesn’t rely on configuration tests, without cluttering ‘configure.in’ any more than necessary.
I should point out that, although this method has served me well for a number of years now, it is inherently fragile because it relies on undocumented internals of both Autoconf and Automake. There is a very real possibility that if you also track the latest releases of GNU Autotools, it may stop working. Future releases of GNU Autotools will address the interface problems that force us to use code like this, for the lack of a better way to do things.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated by Ben Elliston on July 10, 2015 using texi2html 1.82.