Home|| Articles| Projects| Links| Info
Site Logo
Site Logo
GNU Automake By Example
Site Logo

WEB Logo

Table of Contents

  1. Abstract
  2. A Minimal Project
  3. Editing Automake-based Projects with KDevelop
  4. Adding Doxygen Support
  5. A More Complex Example
  6. Topics Not Covered
  7. Links

Abstract

This article presents several simple Automake/Autoconf-based projects. I assume that you know what Automake, Autoconf, and configure are, and that you know how to install a software package from sources (i.e., you know how to invoke "configure & make & make install"). (If you don't, you can still follow the instructions to create a very small project to play around with.) This article does not contain lengthy explanations or detailed background information. Rather, I present a few examples that (hopefully) get the ideas across.

Some of the topics for which examples are presented:

  • Doxygen support
  • Multiple subdirectories
  • Flex/Bison support
  • Libtool Convenience libraries
  • KDevelop Automake Manager

I have tested all examples on GNU/Linux using Automake 1.9.5 and Autoconf 2.59.

I am not an Automake guru myself (not yet ;-). When I ported mfGraph to Automake, I was looking for short and simple examples like those presented in this article that would illustrate what the Automake and Autoconf manuals were talking about. I didn't find exactly what I was looking for. The Automake Book [1], while being a good introduction, didn't answer all my questions either. If you're like me, maybe you'll find this article helpful.

I appreciate all your feedback, especially if you find any errors or abuses of Automake/Autoconf concepts.

A Minimal Project

Create a directry structure with the following files in it:


    foobar/
        m4/
        src/
            Makefile.am
            <your source code files>
        AUTHORS
        COPYING
        ChangeLog
        Makefile.am
        NEWS
        README
        autogen.sh
        configure.ac

This is the source tree of the project. Apart from the .cpp and .h files, these text files are the only files that you need to create for a minimal GNU Automake/Autoconf-based project. All other files will be generated by the tools.

Root Makefile.am

Let's take a look at the contents of the files. The files named Makefile.am are the input to the Automake tool. First, the root Makefile.am:


foobar/Makefile.am:
    ACLOCAL_AMFLAGS = -I m4
    SUBDIRS = src
    EXTRA_DIST = autogen.sh
  • For a minimal project, we only need to name the subdirectories containing additional Makefile.am files.

  • The option -I m4 tells Autoconf to look for additional Autoconf macros in the m4 subdirectory. We'll make use of this when we introduce Doxygen.

  • The EXTRA_DIST directive tells Automake to place the file autogen.sh in the distribution archive, so that that file is shipped to our users.

autogen.sh

The file autogen.sh is a shell script that invokes autoreconf for us. The tool autoreconf is responsible for calling Autoconf, Automake and related tools in the right order.

Don't forget to set the Execute bit for the file autogen.sh!


foobar/autogen.sh:
    #!/bin/sh
    autoreconf --force --install -I config -I m4
  • The --force option rebuilds the configure script regardless of its timestamp in relation to that of the file configure.ac.

  • The option --install copies some missing files to the directory, including the text files COPYING and INSTALL.

  • We add -I config and -I m4 so that the tools find the files that we're going to place in those subdirectories instead of in the project root.

Note: Don't run autogen.sh yet. We have to write configure.ac and Makefile.am first.

For more information on autoreconf, run info autoreconf. If you're using KDE, you can also enter info:autoreconf in the Konqueror address box.

configure.ac

The file configure.ac is the input to Autoconf. Autoconf produces the configure shell script, which, in turn, produces the final Makefiles, so that users can type make install to install your software.


foobar/configure.ac:
    dnl Process this file with autoconf to produce a configure script.
    AC_INIT(foobar, 1.0, me@mail.com)
    AC_CONFIG_AUX_DIR(config)
    AC_CONFIG_SRCDIR(src/foobar.cpp)

    AM_INIT_AUTOMAKE

    AC_PROG_CXX

    AC_OUTPUT(Makefile src/Makefile)
  • The lines up to and including AM_INIT_AUTOMAKE are more or less boilerplate code. AC_CONFIG_AUX_DIR is the place where some helper files will be placed. This keeps the root directory cleaner.

  • AC_PROG_CXX enables C++ compiler support. Autoconf will generate code for the configure script that determines the location of the compiler, tests various compiler switches, etc.

    • Larger projects will require additional checks and switches here.

  • AC_OUTPUT lists the Makefiles that the configure script should generate on the user's machine. For every Makefile.am that we write, Automake will generate a Makefile.in. The configure scripts turns these into Makefiles.

For more information on Autoconf, please see the Autoconf manual (info autoconf).

src/Makefile.am

Each subdirectory has its own Makefile.am. Our file src/Makefile.am builds an executable program from a single C++ source file.


foobar/src/Makefile.am:
    bin_PROGRAMS = foobar
    foobar_SOURCES = foobar.cpp
  • "PROGRAMS" is called a primary. Other primaries include:

    • LIBRARIES for static libraries (.a)
    • LTLIBRARIES for Libtool-based shared libraries (.la)
    • HEADERS
    • ...
  • The prefix "bin_" tells Automake where to copy the resulting program when the user runs make install. Known directory prefixes include:

    • bin_ - for programs, e.g., /usr/local/bin
    • lib_ - where libraries are placed, e.g., /usr/local/lib
    • include_ - where header files are placed, e.g., /usr/local/include
    • pkginclude_ - e.g., /usr/local/include/foobar
    • noinst_ - files that will not be copied anywhere by make install
    • ...

    Note: The user can specify the locations of these directories when running the configure script. For more info, run configure --help.

  • "SOURCES" is a variable that lists the source files of the program. For programs and libraries, possible variables include:

    • CFLAGS, CPPFLAGS, CXXFLAGS - extra arguments passed to the compiler/preprocessor
    • LIBADD - extra objects for a library
    • LDADD - extra objects for a program
    • LDFLAGS - extra arguments passed to the linker
    • ...

For more information on Automake, please see the Automake manual (info automake).

Running the Tools

Now it's time to run the tools and attempt a build.

  1. Run ./autogen.sh and see which files are produced by this step.

  2. Create a separate build tree and run configure:

        > mkdir build
        > cd build
        > ../configure

    Note: You can pass various arguments to configure. Take a look at these by running configure --help.

    Again, see which files are produced by this step.

  3. Run make, then make install.

  4. To produce a distribution package, run make dist or, better yet, make distcheck.

Editing Automake-based Projects with KDevelop

You can work with Automake-based projects from within the KDevelop IDE.

  1. Click Project > Import Existing Project...

  2. Specify the directory that contains your Automake-based project


    (Screenshot taken in KDevelop 3.2.0)

  3. Using the Automake Manager, you can add/remove sub-projects, add/remove files, set options, etc.

  4. If your main program is not named after the project, you need to set the Run Options in Project > Options to be able to debug:

Note: Not everything can be done directly in the IDE. Sometimes you will have to edit the files configure.ac and Makefile.am manually.

Adding Doxygen Support

Doxygen is a tool that generates HTML documentation from special comments in C++ source code. (However, I assume you already know the tool. If you don't, you can safely skip this section.)

Adding Doxygen support means that we want to have a Make target that generates the HTML documentation, and that the generated HTML documentation should be included in the distribution archive. For this to work, you need to download a few files from Oren Ben-Kiki's web site and place them in your directory structure (new files are in boldface):


    foobar/
        m4/
            ac_doxygen.m4
        src/
            Makefile.am
            <your source code files>
        AUTHORS
        COPYING
        ChangeLog
        Makefile.am
        NEWS
        README
        aminclude.am
        autogen.sh
        configure.ac
        doxygen.cfg

Note: Older versions of these files seem to be available at the Autoconf Macro Archive, but these don't work as good.

  • ac_doxygen.m4 contains Autoconf macros that we can use in configure.ac.
  • aminclude.am contains the Doxygen-related make targets.
  • doxygen.cfg is a Doxyfile template that contains a few macros that will be expanded when the configure script is run. Modify the file so that it suits your needs (and the version of Doxygen that you're using!).

Next, we need to make a change to the file Makefile.am in the root directory so that the generated documentation will be included in the distribution archive (added lines are in boldface):


foobar/Makefile.am:
    ACLOCAL_AMFLAGS = -I m4
    SUBDIRS = src

    include aminclude.am

    EXTRA_DIST = autogen.sh $(DX_CONFIG) doc/html

Finally, we add Doxygen-related macro calls to the file configure.ac (added lines are in boldface):


foobar/configure.ac:
    dnl Process this file with autoconf to produce a configure script.
    AC_INIT(foobar, 1.0, me@mail.com)
    AC_CONFIG_AUX_DIR(config)
    AC_CONFIG_SRCDIR(src/foobar.cpp)

    AM_INIT_AUTOMAKE

    AC_PROG_CXX

    DX_HTML_FEATURE(ON)
    DX_CHM_FEATURE(OFF)
    DX_CHI_FEATURE(OFF)
    DX_MAN_FEATURE(OFF)
    DX_RTF_FEATURE(OFF)
    DX_XML_FEATURE(OFF)
    DX_PDF_FEATURE(OFF)
    DX_PS_FEATURE(OFF)
    DX_INIT_DOXYGEN(foobar, doxygen.cfg, doc)

    AC_OUTPUT(Makefile src/Makefile)

Documentation will be generated when you run make doxygen-doc or when you produce a distribution archive with make distcheck.

Note: When you look at the generated Makefile, you'll see that the documentation only depends on the files in pkginclude_HEADERS, regardless of what you set "INPUT" to in the file doxygen.cfg. If you want to force the documentation to be re-generated (maybe before the final build), it might be a good idea to delete the entire Doxygen output folder (doc/html by default) before doing the build.

A More Complex Example

Finally, I'd like to present a more complex example with the following features:

  • Several subdirectories, each with their own Makefile.am
  • Libtool shared and convenience libraries
  • Generated source files (the typical Flex/Bison example)

The new directory structure looks like this (added entries in boldface):


    foobar/
        m4/
            ac_doxygen.m4
        some_shared_lib/
            Makefile.am
            <your some_shared_lib-specific source code files>
        src/
            Makefile.am
            <your source code files>
        AUTHORS
        COPYING
        ChangeLog
        Makefile.am
        NEWS
        README
        aminclude.am
        autogen.sh
        configure.ac
        doxygen.cfg

For Libtool libraries as well as for Flex/Bison, we need additional checks in configure.ac. Also, we must specify the new subdirectory (added text in boldface):


foobar/configure.ac:
    dnl Process this file with autoconf to produce a configure script.
    AC_INIT(foobar, 1.0, me@mail.com)
    AC_CONFIG_AUX_DIR(config)
    AC_CONFIG_SRCDIR(src/foobar.cpp)

    AM_INIT_AUTOMAKE

    AC_PROG_CXX
    AM_PROG_LEX
    AC_PROG_YACC
    AC_PROG_LIBTOOL

    DX_HTML_FEATURE(ON)
    DX_CHM_FEATURE(OFF)
    DX_CHI_FEATURE(OFF)
    DX_MAN_FEATURE(OFF)
    DX_RTF_FEATURE(OFF)
    DX_XML_FEATURE(OFF)
    DX_PDF_FEATURE(OFF)
    DX_PS_FEATURE(OFF)
    DX_INIT_DOXYGEN(foobar, doxygen.cfg, doc)

    AC_OUTPUT(Makefile src/Makefile some_shared_lib/Makefile)

The additional subdirectory must also be added to Makefile.am (added text in boldface):


foobar/Makefile.am:
    ACLOCAL_AMFLAGS = -I m4
    SUBDIRS = src some_shared_lib

    include aminclude.am

    EXTRA_DIST = autogen.sh $(DX_CONFIG) doc/html

In the file src/Makefile.am, we build a Libtool convenience library from the sources in the src directory. A convenience library is a library that is not installed (as specified by the "noinst_" prefix). Such a library is useful whenever you want to link the same set of sources into several executables or shared libraries, without having to list these sources in every Makefile.am.

Another complication in src/Makefile.am is that it includes a Flex/Bison-generated parser. With Automake, you only have to list the Bison grammar file (.yy) and the Flex lexer file (.ll) file; Automake knows how to invoke Flex/Bison to generate the source code.

The only thing you have to remember is to specify mfg_bison.h in BUILT_SOURCES. This way, Automake will run the commands that generate mfg_bison.h before compiling any other files that might depend on it. (Typically, the generated mfg_flex.cpp is one such file that depends on mfg_bison.h. If you don't specify BUILT_SOURCES, it might happen that the Make tool tries to compile mfg_flex.cpp before mfg_bison.h exists.)

We also specify public_api.h in the list pkginclude_HEADERS. When the user runs make install, the listed files will be copied to /usr/local/include/foobar (or a different directory passed to configure).


foobar/src/Makefile.am:
    BUILT_SOURCES = mfg_bison.h
    AM_YFLAGS = -d -p mfg
    AM_LFLAGS = -o$(LEX_OUTPUT_ROOT).c

    noinst_LTLIBRARIES = libsrc.la
    libsrc_la_SOURCES = public_api.cpp mfg_bison.yy mfg_flex.ll

    pkginclude_HEADERS = public_api.h

If we didn't want to install any headers, we'd list the headers in libsrc_la_SOURCES. Headers that are not listed anywhere are not included in the distribution archive.

In the subdirectory some_shared_lib, we link the convenience library, libsrc.la, and an additional source file into a shared library, libfoobar.la, that will be installed to /usr/local/lib (or a different directory passed to configure).

The Makefile.am looks like this:


foobar/some_shared_lib/Makefile.am:
    lib_LTLIBRARIES = libfoobar.la
    libfoobar_la_SOURCES = shared_library.cpp
    libfoobar_la_CPPFLAGS = -I$(top_srcdir)/src
    libfoobar_la_LIBADD = ../src/libsrc.la

I've specified $(top_srcdir)/src as an additional include directory, because it's common to have #include directives for sources found in src in source files such as some_shared_lib/shared_library.cpp. Note that for linking to the convenience library, I specifiy ../src instead. This is because the library will be found in the build tree, not in the source tree.

Topics Not Covered

One topic that I didn't cover but that I'm very much interested in is

  • building and running a unit test suite automatically during a build.

Maybe someone of you has a simple working example?

Links

  1. Gary V. Vaughan, Ben Elliston, Tom Tromey and Ian Lance Taylor. GNU Automake, Autoconf, and Libtool. http://sources.redhat.com/autobook/.
  2. Automake Manual. http://sources.redhat.com/automake/automake.html.
  3. Autoconf Manual. http://www.gnu.org/software/autoconf/manual/index.html.
  4. The GNU Autoconf Macro Archive. http://www.gnu.org/software/ac-archive/.
  5. Oren Ben-Kiki. Doxample. http://ben-kiki.org/oren/doxample/.
  6. This article presents another Automake example: Building SWIG Python Extensions on GNU/Linux

www.geocities.com/foetsch
Copyright © 2005 Michael Fötsch
1