Autotools

1. Motivation

I'm a big fan of the GNU autotools suite, comprising autoconf, automake, libtool, and other tools. They are often considered as hard to use, but when all tools are used from the very beginning of a project, it's actually quite easy. I wrote this tutorial to show the basic steps required to setup an autotools based project. It does not require detailed knowledge of Makefiles or any of these tools to get started.

2. Advantages

The autotools framework is especially beneficial for open source projects. For instance, AutoMake automatically creates Makefile rules to generate release tarballs, containing everything required for the user to rebuild the package. To sum up, here are some key advantages:

3. Prerequisites

You need to install the following packages to make use of all autotools:

4. Getting started

Here is a quick overview of the necessary steps to create a build environment based on the autotools.

4.1. The main program

Consider having the following source code:
#include <stdio.h>

int main( int argc, char **argv )
{
    printf( "Hello World\n" );
    
    return 0;
}
Put this text into a file named hello.c into a src subdirectory. It does not have to be a subdirectory, but it's good thing to put all source files into one directory to have a clean main directory.

4.2. Automake files

Now create the automake files. It is possible to just a single one for the whole project, but we will use a separate Makefile for the src directory.

So first create the top-level file Makefile.am with just the content

SUBDIRS = src
Now in the src directory, create another file Makefile.am with the content
bin_PROGRAMS = hello

hello_SOURCES = hello.c
This just says that there will be one program called "hello" (to be installed in the bin directory), and its sources are just the hello.c file.

4.3. Autoconf files

Now run autoscan to generate a configure template script. It will automatically consider the automake files. Rename the file to configure.ac.

Edit the file and add

AM_INIT_AUTOMAKE
at the end of the first block of lines. This basically says that automake should be initialized too. You should also change the name and version in the AC_INIT line.

GNU autotools require some files to exists, so execute

touch NEWS README AUTHORS ChangeLog
to get those.

The final file will look like this:

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([src/hello.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

4.4. Generate final files

The project is set up so that the tool autoreconf can be used it initialize all necessary tools of the autotools suite. So just execute
autoreconf -i
to let it create all necessary files.

Basically it calls aclocal, automake, autoconf, autoheader in correct order to create all files, but since all tools play well together, autoreconf is just enough.

4.5. Build

Now you can run
./configure && make
to build the program.

5. Extending the project

Once the the basic skeleton is working, adding more source files is easy, just add the Makefile.am and add any file to the *_SOURCES line, it can be c or header files, even from different types (like C or C++ files). Then just call make and the dependencies will take care of recreating the correct Makefiles.

6. Creating a release

Automake automatically adds some Make targets to create release tarballs and even to check if it builds correctly out of that file.

To create a release file, you just need to execute:

make dist
This command will create a tarball named after the project name and version in the configure.ac file.

It's a good idea to let automake check if the release archive is complete and builds. For that, the make target distcheck has been added also. Instead of make dist, execute

make distcheck
It will also create a release archive, but additionally it will extract the archive into a temporary directory and try to run configure && make. The make output will indicate whether or not the build was successful.

7. Adding external libraries

At some point you often want to use additional libraries within your project. Adding those is very easy if they have a pkg-config entry (which most libraries nowadays bring). You can use the following macro in configure.ac to check for a given package and get all relevant compile parameters:
PKG_CHECK_MODULES([SDL2],[sdl2])
The first paramter is an arbitrary name within the configure system. The second name is the actual pkg name. Here we are using libsdl2 (or the sdl2 package to be more specific). In the Makefile.am you can reference the compiler flags and linker flags like this:
hello_CFLAGS = @SDL2_CFLAGS@
hello_LDADD = @SDL2_LIBS@
The prefix SDL2_ is constructed by using the first argument of PKG_CHECK_MODULES, so whatever you put there needs to be used here. It is also possible to check for minimum or exact version, and to add addtional actions when the package is found or not found:
PKG_CHECK_MODULES([CHECK], [check >= 0.9.4], [usetests=yes], [usetests=no])