|[ < ]||[ > ]||[ << ]||[ Up ]||[ >> ]||[Top]||[Contents]||[Index]||[ ? ]|
Deciding what to check for is really the central part of writing ‘configure.in’. Once you’ve read the Autoconf reference manual, the "how"s of writing a particular test should be fairly clear. The "when"s might remain a mystery – and it’s just as easy to check for too many things as it is to check for too few.
One notable area of divergence between various Unix-like systems is that the same programs don’t exist on all systems, and, even when they do, they don’t always work in the same way. For these problems we recommend, when possible, following the advice of the GNU Coding Standards: use the most common options from a relatively limited set of programs. Failing that, try to stick to programs and options specified by POSIX, perhaps augmenting this approach by doing checks for known problems on platforms you care about.
Checking for tools and their differences is usually a fairly small part of a ‘configure’ script; more common are checks for functions, libraries, and the like.
Except for a few core libraries like ‘libc’ and, usually, ‘libm’ and libraries like ‘libX11’ which typically aren’t considered system libraries, there isn’t much agreement about library names or contents between Unix systems. Still, libraries are easy to handle, because decisions about libraries almost always only affect the various ‘Makefile’s. That means that checking for another library typically doesn’t require major (or even, sometimes, any) changes to the source code. Also, because adding a new library test has a small impact on the development cycle – effectively just re-running ‘configure’ and then a relink – you can effectively adopt a lax approach to libraries. For instance, you can just make things work on the few systems you immediately care about and then handle library changes on an as-needed basis.
Suppose you do end up with a link problem. How do you handle it? The
first thing to do is use
nm to look through the system libraries
to see if the missing function exists. If it does, and it is in a
library you can use then the solution is easy – just add another
AC_CHECK_LIB. Note that just finding the function in a library
is not enough, because on some systems, some "standard" libraries are
undesirable; ‘libucb’ is the most common example of a library which
you should avoid.
If you can’t find the function in a system library then you have a somewhat more difficult problem: a non-portable function. There are basically three approaches to a missing function. Below we talk about functions, but really these same approaches apply, more or less, to typedefs, structures, and global variables.
The first approach is to write a replacement function and either
conditionally compile it, or put it into an appropriately-named file and
AC_REPLACE_FUNCS. For instance, Tcl uses
AC_REPLACE_FUNCS(strstr) to handle systems that have no
The second approach is used when there is a similar function with a
different name. The idea here is to check for all the alternatives and
then modify your source to use whichever one might exist. The idiom
here is to use
break in the second argument to
AC_CHECK_FUNCS; this is used both to skip unnecessary tests and
to indicate to the reader that these checks are related. For instance,
here is how
libgcj checks for
inet_addr; it only uses the first one found:
AC_CHECK_FUNCS(inet_aton inet_addr, break)
Code to use the results of these checks looks something like:
#if HAVE_INET_ATON ... use inet_aton here #else #if HAVE_INET_ADDR ... use inet_addr here #else #error Function missing! #endif #endif
Note how we’ve made it a compile-time error if the function does not exist. In general it is best to make errors occur as early as possible in the build process.
The third approach to non-portable functions is to write code such that
these functions are only optionally used. For instance, if you are
writing an editor you might decide to use
mmap to map a file into
the editor’s memory. However, since
mmap is not portable, you
would also write a function to use the more portable
Handling known non-portable functions is only part of the problem, however. The pragmatic approach works fairly well, but it is somewhat inefficient if you are primarily developing on a more modern system, like GNU/Linux, which has few functions missing. In this case the problem is that you might not notice non-portable constructs in your code until it has largely been finished.
Unfortunately, there’s no high road to solving this problem. In the end, you need to have a working knowledge of the range of existing Unix systems. Knowledge of standards such as POSIX and XPG can be useful here, as a first cut – if it isn’t in POSIX, you should at least consider checking for it. However, standards are not a panacea – not all systems are POSIX compliant, and sometimes there are bugs in systems functions which you must work around.
One final class of problems you might encounter is that it is also easy
to check for too much. This is bad because it adds unnecessary
maintenance burden to your program. For instance, sometimes you’ll see
code that checks for
<sys/types.h>. However, there’s no point in
doing that – using this header is mostly portable. Again, this can
only be addressed by having a practical knowledge, which is only really
possible by examining your target systems.
|[ < ]||[ > ]||[ << ]||[ Up ]||[ >> ]|
This document was generated by Ben Elliston on July 10, 2015 using texi2html 1.82.