How To Use Autotools

The autotools infrastructure can be extremely overwhelming to newcomers. I intend here to give a brief tutorial on how to write a C or C++ project that uses autools and automake. I will also cover libtool, which you'll need if you want to ship shared libraries (i.e. .so files.).


By convention you should put your C or C++ code in a directory called src/. Do not put your code in the top level of your project or you will make things a lot harder for yourself.

Once you've got your code basically working, you should run the command autoscan from the root of your project. This tool will automatically scan all of the code in your project and try to come up with a recommended template for you. Typically this will generate two files, autoscan.log and configure.scan. The one you're interested in is configure.scan.

Here's an example of the file it generates in a C++ project I'm currently working on, although your version will almost certainly be different:

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


# Checks for programs.

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([limits.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.
AC_CHECK_FUNCS([getcwd getpagesize memmove strerror strtol])


Rename this file to and then modify it as necessary. At the very minimum, you will have to update the AC_INIT field to fill in the package name, version, and an email address.

One other thing to be aware of is that AC_PREREQ line. That specifies the minimum version of autotools you have to have. Older distrbutions may be on older versions. In particular, a lot of people are still using the Ubuntu 12.04 LTS release ("Precise"), and that has autotools 2.68. So if you want to support older distros you should try running autoscan on an older distro and see what you get. Another thing to be aware of here is that autotools 2.69 is likely to generate a line that says AC_CHECK_HEADER_STDBOOL, and that directive is not supported by autotools 2.68, so you may want to delete it.

I strongly recommend also using the AC_CONFIG_AUX_DIR directive. Here's why. When you run autoreconf it's going to pollute your projefct with a ton of weird scripts that you don't want to check in. If you use AC_CONFIG_AUX_DIR it will instead put all of those weird scripts in the directory you specify, and then you can just add that directory to your .gitignore. The line should look like this, and should immediately follow the AC_CONFIG_SRCDIR line:


Now autoreconf will put all of its weird files in a directory that it will create (if necessary) called ./build-aux.

I strongly recommend using automake. This is pretty easy. You add the following line to your towards the end (I put mine right above the AC_CONFIG_FILES line):

AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])

Obviously you can change the compiler flags here if you want different ones.

If you want to generate shared libraries there is one more line you need to add. You will need to add a line like this:

LT_INIT([shared disable-static])

This tells autoconf that you want to build shared libraries (and not to build static libraries; that's up to you though).

I strongly recommend adding a file called at the root level of your project that will automatically re-generate your ./configure script from A minimal version of that script will look like this:

autoreconf --install

One last thing. You will periodically want to re-run autoscan as your program changes, as autoscan can report errors in your existing file and suggest fixes. For instance, if you start using a new header then you might not have the right macro to detect its presence in your script, and running autoscan will detect this for you and suggest that you add it. I recommend diffing your existing and the newly generated configure.scan and picking the suggested changes that you think make sense.

Library Checking

The autoscan tool doesn't always do a good job of knowing what libraries you need. Therefore you may need to add some of your own checks to your file to check for libraries. Here's an example from a project I'm working on:

# Checks for libraries.
AC_SEARCH_LIBS([dlopen], [dl], [], [
  AC_MSG_ERROR([unable to find dlopen()])
AC_SEARCH_LIBS([cs_disasm_ex], [capstone], [], [
  AC_MSG_ERROR([unable to find libcapstone2])

The first says "check that there is a library called -ldl that has a method named dlopen()". The second says "check that there is a library called -lcapstone that contains a method called cs_disasm_ex()". If your library can be in multiple places you can put multiple parameters in the second option. For instance, some Unixes put dlopen() in -ldld instead of -ldl, so you could check for that like this:

AC_SEARCH_LIBS([dlopen], [dl dld], [], [
  AC_MSG_ERROR([unable to find dlopen()])

In this case it will make your ./configure script check both of those libraries and your code will automatically link against the right one..

Header Checking

If you need certain headers to be present to compile your code then you need to add directives to to check this. You can do this like so:

AC_CHECK_HEADERS([python2.7/Python.h], [], [
  AC_MSG_ERROR([unable to find header Python.h])

This will cause the ./configure script to fail if Python.h isn't found, with an error like this:

checking python2.7/Python.h usability... no
checking python2.7/Python.h presence... no
checking for python2.7/Python.h... no
configure: error: unable to find header Python.h

You have to be pretty careful when doing this because different operating systems will put headers in different places. For instance, some distributions might put Python.h directly in /usr/include instead of /usr/include/python2.7/ as in this example. If you want to handle all of these cases the code can get pretty complex. I would recommend using Google or GitHub search to search for files containing the header you're looking for, and then use someone else's code to get an idea of what you should do.

Configuring Automake (and Libtool)

You're almost done! Now you just need to make two files. One will go at the root of your project, the other will go in your src directory.

The at the root of your project will look like this:


There's more stuff you can put in here, but that's beyond the scope of this post.

The file src/ is where your real logic will be. It might look something like this for a very simple C++ project.

AM_CXXFLAGS = -g -std=c++11 -Wall -fPIC

libpymemtrace_la_SOURCES =

bin_PROGRAMS = pymemtrace
pymemtrace_SOURCES =

This says we want to build a libtool shared library called, and we also want to build a binary executable called pymemtrace. If you're not interested in using libtool then omit those lines.

In the _SOURCES lines you need to list all of the source files, just like a regular Makefile. If you have a complex project that reuses multiple files for multiple targets you can create variables to simplify things, just like in regular Makefiles.

If you're using libtool, there's one more idiosyncrasy you need to be aware of. If you have source files that are used both by the library you're building and the executable you're using then you'll get an error when running autoreconf (which is run by your script). You'll see an error line like this:

src/ error: object 'util.$(OBJEXT)' created both with libtool and without

This is really easy to fix, there's a page in the automake manual about this topic that I'll refer you to. Basically you just need to add a line like this for a C project:




for a C++ project. Replace prog with the actual program you're using.

Building Your Project

If you've made it this far you should be able to build your project like this:


Binary programs will be generated in src/, libtool libraries will be generated in src/.libs/. If your binary links against the libtool library, the "binary" you get in src/ will actually be a stub shell script that sets up LD_LIBRARY_PATH and whatnot and then runs the true binary which is in src/.libs/. If you're not linking against the libtool library you'll just get a regular executable in src/. Normally this will be totally transparent to you, but I mention it because if you want to examine core dumps in GDB you'll need to give GDB the true program which will be something like src/.lib/myprog.

Distributing Source Tarballs

I recommend not checking in any of the autogenerated files in your project. There's going to be a lot of them, they're just boilerplate, and they're going to change when you update autoconf or automake. You do need to ship them when if you are distributing a source tarball intended for end users who want to compile your project, but that's easy. You run:

make dist

And it will create a file named programname-version.tar.gz that has all of the files required for end users to build your project.

Update: 2016-02-23

I've since learned how to use PKG_CHECK_MODULES which I strongly recommend for packages that are configured for usage with pkg-config. This mean's you'll need a file named foo.pc on your computer for libfoo. Here's what I'm using in a current work project:


You would use this instead of the previous pattern that I had suggested (in the case of Capstone):

AC_SEARCH_LIBS([cs_disasm_ex], [capstone], [], [
  AC_MSG_ERROR([unable to find libcapstone2])
AC_CHECK_HEADERS([capstone/capstone.h], [], [
  AC_MSG_ERROR([unable to find header capstone.h])