Chapter 5. AUTOMATIC MAKEFILES WITH AUTOMAKE

If you understand, things are just as they are; if you do not understand, things are just as they are.

image with no caption

Shortly after Autoconf began its journey to success, David MacKenzie started working on a new tool for automatically generating makefiles for a GNU project: Automake. During early development of the GNU Coding Standards, it became apparent to MacKenzie that because the GCS is fairly specific about how and where a project's products should be built, tested, and installed, much of a GNU project makefile was boilerplate material. Automake takes advantage of this fact to make maintainers' lives easier.

MacKenzie's work on Automake lasted almost a year, ending around November 1994. A year later, in November 1995, Tom Tromey (of Red Hat and Cygnus fame) took over the Automake project and played a significant role in its development. Although MacKenzie wrote the initial version of Automake in Bourne shell script, Tromey completely rewrote the tool in Perl and continued to maintain and enhance Automake over the next five years.

By the end of 2000, Alexandre Duret-Lutz had essentially taken over maintenance of the Automake project. His role as project lead lasted until about mid-2007, and since then, the project has been maintained by Ralf Wildenhues,[66] with occasional input from Akim Demaille and Jim Meyering.

Most of the complaints I've seen about the Autotools are ultimately associated with Automake. The reasons are simple: Automake provides the highest level of abstraction over the build system, and imposes a fairly rigid structure on projects that use it. Automake's syntax is concise—in fact, it's terse, almost to a fault. One Automake statement represents a lot of functionality. But once you understand it, you can get a fairly complete, complex, and functionally correct build system up and running in short order—that is, in minutes, not hours or days.

In this chapter, I'll provide you with some insight into the inner workings of Automake. With such insight, you'll begin to feel comfortable not only with what Automake can do for you but also with extending it in areas where its automation falls short.

Let's face it—getting a makefile right is often difficult. The devil, as they say, is in the details. Consider the following changes to the files in our project directory structure, as we continue to improve the project build system for Jupiter:

❶ $ rm autogen.sh Makefile.in src/Makefile.in
❷ $ echo "SUBDIRS = src" > Makefile.am
❸ $ echo "bin_PROGRAMS = jupiter
  > jupiter_SOURCES = main.c" > src/Makefile.am
❹ $ touch NEWS README AUTHORS ChangeLog
  $ ls −1
  AUTHORS
  ChangeLog
  configure.ac
  Makefile.am
  NEWS
  README
  src
  $

The rm command at ❶ deletes our hand-coded Makefile.in templates and the autogen.sh script we wrote to ensure that all the support scripts and files are copied into the root of our project directory. We won't need this script anymore, because we're upgrading Jupiter to Automake proper. (For the sake of brevity, I've used echo statements at ❷ and ❸ to write the new Makefile.am files; you can use a text editor if you wish.)

Note

There is a hard carriage return at the end of the line at ❸. The shell will continue to accept input after the carriage return until the quotation is closed.

I've used the touch command at ❹ to create new, empty versions of the NEWS, README, AUTHORS, and ChangeLog files in the project root directory. (The INSTALL and COPYING files are added by autoreconf -i.) These files are required by the GCS for all GNU projects. And although they're not required for non-GNU programs, they've become something of an institution in the OSS world; users have come to expect them.

To enable Automake within the build system, I've added a single line to configure.ac: a call to AM_INIT_AUTOMAKE between the calls to AC_INIT and AC_CONFIG_SRCDIR, as shown in Example 5-1.

If your project has already been configured with Autoconf, this is the only line that's required to enable Automake, besides the normal requirements of an Autoconf input file. The AM_INIT_AUTOMAKE macro accepts an optional argument: a whitespace-separated list of option tags, which can be passed into this macro to modify the general behavior of Automake. For a detailed description of each option, see Chapter 17 of the GNU Automake Manual.[68] I will, however, point out a few of the most useful options here.

check-news

The check-news option causes make dist to fail if the project's current version (from configure.ac) doesn't show up in the first few lines of the NEWS file.

dist-bzip2, dist-lzma, dist-shar, dist-zip, dist-tarZ

You can use the dist-* options to change the default distribution package type. By default, make dist builds a .tar.gz file, but developers often want to distribute, for example, .tar.bz2 packages instead. These options make the change quite easy. (Even without the dist-bzip2 option, you can override the current default by using make dist-bzip2, but using the option is simpler if you always want to build .bz2 packages.)

readme-alpha

The readme-alpha option temporarily alters the behavior of the build and distribution processes during alpha releases of a project. Using this option causes a file named README-alpha, found in the project root directory, to be distributed automatically. The use of this option also alters the expected versioning scheme of the project.

-Wcategory, --warnings=category

The -Wcategory and --warnings=category options indicate that the project would like to use Automake with various warning categories enabled. Multiple such options can be used with different category tags. Refer to the GNU Automake Manual to find a list of valid categories.

silent-rules

The silent-rules feature causes Automake to generate makefiles that allow the user to specify that only the toolname and output filename are sent to stdout during the build. The resulting output looks something like this:

$ make
  CC     foo.o
  CXX    bar.o
  ...
  CXXLD  prog
$
parallel-tests

The parallel-tests feature allows checks to be executed in parallel in order to take advantage of multiprocessor machines during execution of the check target.

version

The version option is actually a placeholder for a version number that represents the lowest version of Automake that is acceptable for this project. For instance, if 1.11 is passed as an option tag, Automake will fail while processing configure.ac if its version is earlier than 1.11. This can be useful if you're trying to use features that only exist in the latest version of Automake.

With the new Makefile.am files in place and Automake enabled in configure.ac, let's run autoreconf with the -i option in order to add any new utility files that Automake may require for our project:

$ autoreconf -i
configure.ac:6: installing `./install-sh'
configure.ac:6: installing `./missing'
src/Makefile.am: installing `./depcomp'
Makefile.am: installing `./INSTALL'
Makefile.am: installing `./COPYING'
Makefile.am:     Consider adding the COPYING file to the version control system
Makefile.am:     for your code, to avoid questions about which license
 your project uses.
$
$ ls −1p
aclocal.m4
AUTHORS
autom4te.cache/
ChangeLog
config.h.in
configure
configure.ac
COPYING
depcomp
INSTALL
install-sh
Makefile.am
Makefile.in
missing
NEWS
README
src/
$

Adding the AM_INIT_AUTOMAKE macro to configure.ac causes autoreconf -i to now execute automake -i, which includes a few more new utility files: aclocal.m4, install-sh, missing, and depcomp. Additionally, Automake now generates Makefile.in from Makefile.am.

Automake also adds default INSTALL and COPYING text files containing boilerplate text that pertains specifically to the GNU project. You can modify these files for your projects as you see fit. I find the default INSTALL file text to be useful for general-purpose instructions related to Autotools-built projects, but I like to prepend some project-specific information to the top of this file before committing it to my repository. Automake's -i option won't overwrite these text files in a project that already contains them, so feel free to modify the default files as you see fit, once they've been added by autoreconf -i.

The COPYING file contains the text of the GPL, which may or may not apply to your package. If your project is released under GPL, just leave the text as is. If you're releasing under another license, such as the BSD, MIT, or Apache Commons licenses, replace the default text with text appropriate for that license.[69]

Note

You only need to use the -i option once in a newly checked-out work area or a newly created project. Once the missing utility files have been added, you can drop the -i option in future calls to autoreconf.

The commands listed above create an Automake-based build system that contains everything we wrote into our original Makefile.in templates, except that this system is more correct and functionally complete according to the GCS. A glance at the resulting generated Makefile.in template shows that Automake has done a significant amount of work for us. The resulting top-level Makefile.in template is nearly 18KB, while the original, hand-coded makefiles were only a few hundred bytes long.

An Automake build system supports the following important make targets (derived from an Automake-generated Makefile):

all

distdir

install

install-strip

install-data

install-exec

uninstall

install-dvi

install-html

install-info

install-ps

install-pdf

installdirs

check

installcheck

mostlyclean

clean

distclean

maintainer-clean

dvi

pdf

ps

info

html

tags

ctags

dist

dist-bzip2

dist-gzip

dist-lzma

dist-shar

dist-zip

dist-tarZ

As you can see, this goes far beyond what we could provide in our hand-coded Makefile.in templates. Automake writes this base functionality into every project that uses it.

In Dependency Rules in Automatic Variables we discussed make dependency rules. These are rules we define in makefiles so that make is aware of the hidden relationships between C-language source files and included header files. Auto-make goes to a lot of trouble to ensure that you don't have to write such dependency rules for languages it understands, like C, C++, and Fortran. This is an important feature for projects containing more than a few source files.

Writing dependency rules by hand for dozens or hundreds of source files is both tedious and error prone. In fact, it's such a problem that compiler writers often provide a mechanism that enables the compiler to write these rules automatically based on its internal knowledge of the source files and the language. The GNU compilers, among others, support a family of -M options (i.e., -M, -MM, -MF, -MG, and so on) on the command line. These options tell the compiler to generate a make dependency rule for the specified source file. (Some of these options can be used on the normal compiler command line, so the dependency rule can be generated when the source file is being compiled.)

The simplest of these options is the basic -M option, which causes the compiler to generate a dependency rule for the specified source file on stdout and then terminate. This rule can be captured in a file, which is then included by the makefile so that the dependency information within this rule is incorporated into the directed graph that make builds.

But what happens on systems where the native compilers don't provide dependency generation options, or where they don't work together with the compilation process? In such cases, Automake provides a wrapper script called depcomp that executes the compiler twice: once for dependency information, and again to compile the source file. When the compiler lacks the options to generate any dependency information, another tool may be used to recursively determine which header files affect a given source file. On systems where none of these options are available, automatic dependency generation fails.



[66] I owe many heartfelt thanks to Ralf for kindly answering so many seemingly trivial questions while I worked on this book.

[67] This information is taken from the March 27, 2010 version of the GNU Coding Standards at http://www.gnu.org/prep/standards/.

[68] See the Free Software Foundation's GNU Automake Manual at http://www.gnu.org/software/automake/manual.

[69] See the Open Source Initiative website at http://opensource.org/ for current license text for nearly all known open source licenses.