Autoconf/Automake Howto

TOC

Introduction

autoconf and automake are two utilities to make porting applications and setting them up for individual computers easier. However, getting started is a daunting task. It is not clear, since these are two separate packages, what needs to be done first, and how to create the configure.in and Makefile.am files.

If you have autoconf and automake installed on your system, you should be able to read the documentation using an info browser. The documentation is complete, but more for reference than instruction.

This document attempts to act as a tutorial for autoconf and automake for those who never used them before.

Requirements

You will need the following packages: (if not already there, install them in this order)

  1. gnu c compiler (really. other compilers won't work because autoconf uses some gcc "features". If you really can't get gcc in, don't sweat it. Just use the -i flag in automake.)
  2. gnu m4 (used by autoconf)
  3. perl (used by automake and autoscan)
  4. autoconf (supplies autoscan, autoconf and autoconf's macros)
  5. automake (automake also supplies aclocal)

Optional packages: gnu tar, texinfo, gnu make, gettext, and libtool. But I won't go there.

Note: if you don't use gnu tar, you may get a .tar.gz file which is in tar format, but not compressed. You will need to rename it to .tar and compress it by hand.

Dependencies

Since the intended audience should know how a Makefile is constructed, I will show the dependancies with a psuedo-makefile. It should be easy to determine which functions are run, when they need to be run, and what files they create. Those files in strong type are created by the developer. All other files are either derived, or supplied by automake and autoconf.


aclocal.m4 : configure.in acinclude.m4
    aclocal

configure : configure.in aclocal.m4 $(optional)
    autoconf

am_args = -i --foreign -a
Makefile.in : Makefile.am configure.in aclocal.m4
    automake $(am_args)

#config.h.in is optional
optional=acconfig.h config.h.top config.h.bot
config.h.in : configure.in $(optional)
    autoheader

config.status config.cache config.log config.h Makefile : \
    Makefile.in
        configure

Steps to get started

The following are the minimal steps to create a configuration using autoconf/automake.

  1. Create your C sources. See portability for portability issues.
  2. Create your Makefile.am. See Makefile.am examples.
  3. run autoscan and copy configure.scan to configure.in
  4. Add AM_INIT_AUTOMAKE(prog, version) to configure.in right after AC_INIT where prog is the name of the program you are building and version is the release number.
  5. Add AC_PROG_CC to configure.in (if you use a C compiler)
  6. If this is a deep configuration, you should add AC_PROG_MAKE_SET and (for libraries) AC_PROG_RANLIB
  7. Add Makefile [ src/Makefile ...] to AC_OUTPUT (see Chicken and the egg)
  8. run aclocal to create aclocal.m4
  9. run autoconf
  10. Optionally run autoheader (see autoheader example to use config.h)
  11. Run automake -a --foreign (unless you are REALLY making a gnu distribution. Then leave off the --foreign and add the gnu specific files. (see the automake info file.)) If you are not using gnu c, add the -i switch.
  12. Test the configuration. run:
    1. ./configure
    2. make
    3. make dist
  13. distribute the prog-version.tar.gz file. see note.

Autoheader example

The following is similar to the above example, but it uses autoheader. After running aclocal:

  1. Put #ifdef HAVE_CONFIG_H #include <config.h> #endifin your source file(s)
  2. make an acconfig.h file containing#undef VERSION #undef PACKAGE
  3. place AM_CONFIG_HEADER(config.h) in your configure.in right after AM_INIT_AUTOMAKE
  4. Run autoheader
  5. Continue autoconf procedure.

Examples

Shallow configuration example

A shallow configuration is one that has only one directory. Here is a sample.

Files:


/* hello.c */ #include <stdio.h> int main() { printf("hello world\n"); exit(0); }
##Makefile.am bin_PROGRAM = hello hello_SOURCES = hello.c

After modifying configure.in, it should look like this:


dnl Process this file with autoconf to produce a configure script. AC_INIT(hello.c) AM_INIT_AUTOMAKE(hello, 1.1) dnl Checks for programs. AC_PROG_CC dnl Checks for libraries. dnl Checks for header files. dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for library functions. AC_OUTPUT(Makefile)

Deep example

A deep configuration has subdiretories, and possibly sudirectories of subdirectories. You get the idea. Here is a short example (with libraries).


## Makefile.am SUBDIRS = lib src
## lib/Makefile.am noinst_LIBRARIES = libexample.a libexample_a_SOURCES = libsrc.c
/* lib/libsrc.h */ char * greeting();
/* lib/libsrc.c */ char * greeting() {return "hello world\n";}
## src/Makefile.am hello_SOURCES = hello.c bin_PROGRAMS = hello LDADD = -L../lib -lexample INCLUDES = -I$(top_builddir)/lib
/* src/hello.c */ #include <stdio.h> #include "libsrc.h" int main() { printf(greeting()); }

Follow the steps above and you should get a configure.in like this:

dnl Process this file with autoconf to produce a configure script. AC_INIT(lib/libsrc.c) AM_INIT_AUTOMAKE(hello, 1.1) dnl Checks for programs. AC_PROG_CC AC_PROG_RANLIB dnl Checks for libraries. dnl Checks for header files. dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for library functions. AC_OUTPUT(Makefile src/Makefile lib/Makefile)

That is about as simple as it gets.


Useful variables

Here are some useful variables you will need to use in your Makefile.am. To set the value of the variable, use name = value. Do not set variables marked with @@. This will be set at configuration time (./configure)

To use the value of a variable use $(name).

All variables are case-sensitive. Uppercase letters are not the same as lower case letters.

Directory variables

bindir @@
The directory where the binaries will be installed. This is usually $(exec_prefix)/bin. exec_prefix is commonly $(prefix).
libdir @@
The directory where libraries will be installed. This is usually $(exec_prefix)/lib
top_srcdir @@
The directory at the top of the build tree.
srcdir @@
The directory containing the sources. This is usually the current directory.

lists

bin_PROGRAMS
A space separated list of programs to be installed into the bindir
SUBDIRS
Only used in a top level Makefile.am. A space separated list of the subdirectories which need to be built.
lib_LIBRARIES
Libraries to be installed in the libdir
libname_ext_SOURCES
List of sources to build library libname.ext listed in lib_LIBRARIES.
Note: all dashes and periods (and any other non-alphanumerics) must be changed to underscores.

More variables can be found in automake's info file under Generalities -> Uniform

Configuration options

Yes, it is nice to be able to enable and disable options at configure time like ./configure --enable-threads, but it will likely take about 2 hours of reading through the manuals to figure out all the bits and pieces. Here is a quick look at how to implement configuration options.

This example will demonstrate how to implement a simple(ton) --enable-threads configuration option. We will start with the "C" program's implementation. It will most likely have a conditional based on a "define" value, like so:

#if defined(USE_THREADS) pthread_create(thread, attr, function, arg); #else function(arg); #endif /* USE_THREADS */

There is also a difference in the way the program is linked and compiled:

Without threads:

cc -c prog.c cc -o prog prog.o

With threads:

cc -c -pthread prog.c cc -o prog prog.o -lpthread

To handle these differences, we will set LDADD and CFLAGS in Makefile.am, conditionally.

First, to make a #define from configure.in:

AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [make a threading prog (default is no)]), ac_enable_threads=$enableval, ac_enable_threads=no) if test "$ac_enable_threads" = yes; then AC_DEFINE(USE_THREADS, 1, [use threads]) fi

The AC_HELP_STRING will print out the option and description when ./configure --help is typed.

Next, put in a conditional for automake (still in configure.in)

AM_CONDITIONAL(THREADS, test $ac_enable_threads = yes)

Now, we have a conditional #define for the "C" program and a conditional for the Makefile.am. Next, we will modify Makefile.am to make use of the AM_CONDITIONAL

if THREADS threads_LIB = -lpthread threads_CFLAGS = -pthread else threads_LIB = threads_CFLAGS = endif LDADD = $(threads_LIB) CFLAGS = $(threads_CFLAGS)

Portability issues

You can find some of the common portability issues from the autoconf info page under Existing Tests. This topic will give instructions on how to configure if you use particular programs, libraries, library functions, headers, structures, typedefs, compiler characteristics, system services, and UNIX variants.

autoscan will automatically find any programs, library functions, header files, structures, etc. which might need to be conditionally configured. It will place the autoconf macros in configure.scan. If you see a macro inserted by autoscan, you should check the documentation on the macro in the autoconf info page for more information on how to implement the configuration check.

Chicken and the Egg

The chicken and the egg is a creationist's problem. If God had made every living creature at the same time, did the chicken come first, who laid the egg, or did the egg come first which hatched into a chicken. Either way, one could not have existed unless the other had first existed.

In the case of autoscan and automake, it is almost a chicken and egg proposal. The main difference is that automake will not run without a configure.in, where autoscan will run without complaining without a Makefile.in. The only problem with running autoscan without a Makefile.in is that there are no files placed in AC_OUTPUT. That is why, on the initial configuration, the AC_OUTPUT(Makefile [ src/Makefile ...]) must be placed in the configure.in by hand.