Autoconf is a system for generating a script which will automatically determine the presence of things which your project either depends upon, or can make use of. Once these have been determined, autoconf can export this information in various formats suitable for your project to use. Autoconf scripts themselves are written in a combination of shell and M4 (a macro processing language considerably more capable than the C preprocessor). Autoconf essentially runs the preprocessor on your script to produce a portable shell script which will perform all the requisite tests, produce handy log files and take a standard set of command line arguments.
If you already have a project and are currently writing tests using your own ad-hoc system, I strongly recommend you to switch to Autoconf. The longer you leave it, the more painful your own system will become, and the harder switching to another system (i.e. Autoconf) will be. I say this from personal experience.
There are several tools in the suite, including automake (for automatically generating makefiles) and autoscan (for scanning source trees to make configure scripts). I'm not going to cover them.
In order to read this tutorial, a knowledge of shell scripting is assumed, but not essential for the basic examples. No knowledge of M4 is needed, but it worth knowing especially if you want to write your own custom tests which you wish to reuse.
Finally, this is not a reference work (use the Autoconf documentation for that), it is a tutorial, and is designed to be read through in order. All of the configure script examples are complete scripts which should compile and run.
Save the following script to configure.ac
:
AC_INIT(myconfig, version-0.1) AC_MSG_NOTICE([Hello, world.])Now do:
autoconf configure.ac > configure chmod +x configure ./configureand you get:
configure: Hello, world.
Now that that's out of the way, there's a few basic things.
changequote(<<,>>)
to change the quoting to << and >>. The autoconf
documentation (rightly, in my opinion) warns against the
(over) use of this, since it can lead to unexpected
results.
test
instead. Anyway my
suggestion here is that for the moment, avoid square brackets
where possible. If you do need them, and it isn't working as
expected, examine the output of autoconf and consult the
documentation.
configure.ac
,
since they're Autoconf scripts (just like .c
files are
C programs). It's still common to see them called
configure.in
, but this is discouraged, since in
Autotools, .in
files are used for other things (as
you'll find out later).
AC_INIT(myconfig, version-0.1) echo " Testing for a C compiler" AC_PROG_CC echo " Testing for a C++ compiler" AC_PROG_CXX echo " Testing for a FORTRAN compiler" AC_PROG_F77 AC_LANG(C++)If you run this configure script you should get a bunch of output about testing for each of the three languages in question. The last instruction tells Autoconf that we're working in C++, so all the test programs will be compiled with the C++ compiler as opposed to the C compiler. You can, of course, omit tests for languages which you're not using.
AC_INIT(myconfig, version-0.1) AC_PROG_CXX AC_LANG(C++) AC_CHECK_HEADERS(iostream)Run the script, and at the bottom, you should see the test for the script succeeding. You can check for multiple headers using
AC_CHECK_HEADERS([header1.h header2.h])
cos
in the maths library try the following:
AC_INIT(myconfig, version-0.1) AC_PROG_CC AC_CHECK_LIB(m, cos)
This will compile and link a program looking a bit like like this:
char cos (); int main () { cos (); return 0; }If you want to see exactly what the program looks like, then create a test which you know will fail and examine
config.log
. If you're
running out of ideas of which function to test for, then test for
main
.
confdefs.h
, which is cleaned up at the end. If you copy this
file before the end, you can keep its contents. The following script does
just that:
AC_INIT(myconfig, version-0.1) AC_PROG_CC AC_CHECK_LIB(m, cos) AC_CHECK_HEADER(unistd.h) AC_CHECK_HEADER(b0rk.h) AC_DEFINE(my_own_define, yes) cp confdefs.h my_config.hYou'll now have a file called
my_config.h
looking like:
#define HAVE_INTTYPES_H 1 #define HAVE_LIBM 1 #define HAVE_MEMORY_H 1 #define HAVE_STDINT_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRINGS_H 1 #define HAVE_STRING_H 1 #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_UNISTD_H 1 #define PACKAGE_BUGREPORT "" #define PACKAGE_NAME "myconfig" #define PACKAGE_STRING "myconfig version-0.1" #define PACKAGE_TARNAME "myconfig" #define PACKAGE_VERSION "version-0.1" #define STDC_HEADERS 1 #define my_own_define yesNotice how we have
HAVE_UNISTD_H
and HAVE_LIBM
,
which are the tests performed successfully. Also notice how
HAVE_B0RK_H
is missing. You now have a working configure
script. If you only have a few simple tests to perform, are happy to
#include "my_config.h"
, and perform all of your logic in the C
preprocessor, then you can probably stop reading now and start coding. If
not, then pay particular attention to how we we got our own
#define
in to the file.
This works, is quick and easy to use, but confdefs.h
is not
considered an ``exported'' interface. I have now been told that doing this
is not good practice, and that you should do things properly, as described
in the next section. I am leaving it in, however, since you may well
encounter this when examining other scripts for ideas (which is where I got
the idea from).
???.ac
producing an output file with the .ac
suffix stripped off, and all instances of @foo@
replaced with
the contents of the variable foo
. Here's an example. Create the
following configure.ac
:
AC_INIT(myconfig, version-0.1) AC_PROG_CC AC_SUBST(stuff, hello) AC_OUTPUT(test)and create the following file called
test.in
:
Prefix: @prefix@ C compiler: @CC@ Stuff: @stuff@Run the configure script and examine the contents of
test
. It
should look like this:
Prefix: /usr/local C compiler: gcc Stuff: helloAs you can see, a standard option (prefix) was set, a tested for option (the C compiler) was set, and one of out own substitutions was made, using
AC_SUBST
. It is at this point that the
script begins to accept standard command line arguments as well. Try
running:
./configure CC=g77 --prefix=/tmpand examining the output file (it is a quirk of GCC that g77 will compile C programs). You will get:
Prefix: /tmp C compiler: g77 Stuff: helloThis tutorial is not about writing makefiles, either, but if you already know how to write a makefile, it should be clear now how you can generate a working make file which uses the correct C compiler, install directory, etc...
config.log
contains a complete list of the substitutions
in the "Output variables" section.
Note that tests for libraries and header files do not
appear in the list of substitutions to be made.
One further useful point to note: now that you have used
AC_OUTPUT
, there is a file created called
config.status
. If you alter any of the .in
files,
you only need to run config.status
as opposed to the whole
configure script. This speeds things up greatly when debugging.
config.log
:
AC_INIT(myconfig, version-0.1) AC_PROG_CC AC_CHECK_LIB(m, cos) AC_CHECK_HEADER(unistd.h) AC_CHECK_HEADER(b0rk.h)You should find the following section:
ac_cv_c_compiler_gnu=yes ac_cv_env_CC_set= ac_cv_env_CC_value= ac_cv_env_CFLAGS_set= ac_cv_env_CFLAGS_value= ac_cv_env_CPPFLAGS_set= ac_cv_env_CPPFLAGS_value= ac_cv_env_CPP_set= ac_cv_env_CPP_value= ac_cv_env_LDFLAGS_set= ac_cv_env_LDFLAGS_value= ac_cv_env_build_alias_set= ac_cv_env_build_alias_value= ac_cv_env_host_alias_set= ac_cv_env_host_alias_value= ac_cv_env_target_alias_set= ac_cv_env_target_alias_value= ac_cv_exeext= ac_cv_header_b0rk_h=no ac_cv_header_inttypes_h=yes ac_cv_header_memory_h=yes ac_cv_header_stdc=yes ac_cv_header_stdint_h=yes ac_cv_header_stdlib_h=yes ac_cv_header_string_h=yes ac_cv_header_strings_h=yes ac_cv_header_sys_stat_h=yes ac_cv_header_sys_types_h=yes ac_cv_header_unistd_h=yes ac_cv_lib_m_cos=yes ac_cv_objext=o ac_cv_prog_CPP='gcc -E' ac_cv_prog_ac_ct_CC=gcc ac_cv_prog_cc_g=yes ac_cv_prog_cc_stdc= ac_cv_prog_egrep='grep -E'Some of these will be relevant to the tests, such as
ac_cv_lib_m_cos=yes
. These are all defined shell variables (not
environment variables), and can be used in the following manner:
AC_INIT(myconfig, version-0.1) AC_PROG_CC AC_CHECK_LIB(m, cos) AC_CHECK_HEADER(unistd.h) AC_CHECK_HEADER(b0rk.h) if test "$ac_cv_header_b0rk_h" == no then AC_MSG_WARN([Error, the b0rk header is missing!]) fiThis script should print a warning message if
b0rk.h
is missing
(which it really should be). You can test this further by creating an empty
file called b0rk.h
and running:
./configure CPPFLAGS="-I ."The warning should now be absent. The variables set by autoconf are rather long and cumbersome, but there is a way around this. All of the
AC_CHECK_*
macros take optional
arguments for success and failure:
AC_INIT(myconfig, version-0.1) AC_PROG_CC AC_CHECK_HEADER(b0rk.h, [echo "OK!!"], [echo "Failed!!"])test this as above. This can lead to the following idiom which is useful if a feature depends on many things at once:
AC_INIT(myconfig, version-0.1) AC_PROG_CC a=1 AC_MSG_NOTICE([Checking for b0rk and its requirements.]) AC_CHECK_LIB(m, cos, [], [a=0]) AC_CHECK_HEADER(sys/ioctl.h, [], [a=0]) AC_CHECK_LIB(c, vsnprintf, [], [a=0]) AC_CHECK_HEADER(b0rk.h, [], [a=0]) if test $a == 0 then AC_MSG_NOTICE([Feature b0rk is missing.]) else AC_MSG_NOTICE([Feature b0rk is present.]) fiIf any one of the tests fails, then the test for b0rk fails too. You may wish to print out a helpful error message here. Of course, you can use all of the other shell logic constructs (NB don't forget to use
test
as opposed to [
, otherwise you will get some
very strange errors). At this point it is well worth reading "Portable
Shell Programming" in the Autoconf documentation, otherwise your configure
script may be of less use than you think.
AC_*_IFELSE
can test for a variety of things and provide
success and failure arguments to be executed. Such things include
compilation and linking. These tests are useful if, for example
AC_CHECK_LIB
is insufficient.
AC_PROG_*
tests for standard programs (a large number
are available--search the autoconf documentation). These accept a list
of programs to test for, such as:
AC_PROG_AWK(mawk gawk nawk tawk fawk bawk hawk cawk pawk)
AC_CKECK_PROG
can be used if a specific check for your
program does not exist.
AC_CHECK_*
can be used to check for a wide variety of
parameters (such as the presence of members of structures, sizes of data
elements, etc)
AC_INIT(myconfig, version-0.1) AC_ARG_WITH(stuff, [ --with-stuff enable stuff]) if test "$with_stuff" == "yes" then AC_MSG_NOTICE([You enabled stuff. Good for you.]) elif test "$with_stuff" != "" then AC_MSG_NOTICE([Your specific kind of stuff is $with_stuff]) else AC_MSG_NOTICE([No stuff for you.]) fiTry running the script with
--with-stuff
and
--with-stuff=hello
. Also run ./configure --help
and see your argument appear. You need to use this macro to perform
--without-*
tests as well, but you have to invert your shell
logic afterward.
CFLAGS
(for the C compiler),
CPPFLAGS
(for the C preprocessor, C and C++ compilers),
CXXFLAGS
(for the C++ compiler) and
LIBS
(for the linker).
Whatever is appended to these flags will be exported as a substitution if
the configure script terminates correctly. It is common to do that when you
allow the user to specify paths to optional libraries.
If you really need to, you can
run the compiler directly with $CC.
AC_INIT(myconfig, version-0.1) AC_MSG_CHECKING([for a Pentium III processor]) if grep -q "Pentium III" /proc/cpuinfo then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) AC_MSG_ERROR([I can't work on anything but a PIII processor.]) fiThis performs a completely nonstandard test, but it looks like a standard one, from the outside. The script will fail with an error if the test fails.
Care needs to be taken in order to ensure that the tests are portable, or at lease to not fail catastrophically on different systems.
config.guess
to be distributed with your program. This
will should be installed somewhere as part of your autoconf installation.
Updated September 14th 2016, 04:23