6. Autoconf Building Blocks: Macros

The configuration stages of different software packages are never entirely unique. There are repetitive, similar (if not outright identical) tasks that have to be completed for different packages, with more or less sharing between them.

To avoid repeating the same code over and over, most programming languages provide the facility of functions; m4 instead, being a macro language, provides macros, which share not only the name but also most of the details with the C preprocessor macros: they are expanded inline, they don't have their own variables' scope, the parameters are not typed, and so on.

Note

Confusingly enough, the macro to define new macros is called AC_DEFUN which often confuses the developers into thinking about them in terms of functions. This can lead to many problems, which is why I suggest to always explicitly think and talk about them in terms of macros.

6.1. External Macro Files

Since autoconf macros are often developed to solve generic problems, rather than specific problems of a project (otherwise direct M4sh code would be good enough for most uses), they are often shared across packages and across projects.

In the past, most packages shipped their own macro file with a standardised macro to search for them in a system at build time, making use of particularities of the package, or through configuration helper scripts. For most projects these have been phased out in favour of pkg-config.

There are, though, reusable macros, shipped with various projects or present in archives, such as the Autoconf Archive. Depending on the nature of the macro, the file where it is written is either installed in the system (to be used by autoconf directly) or is simply available to be picked up from the source distribution.

To take two examples, the pkg.m4 file that is shipped with pkg-config is installed in the system, while the attributes.m4 macro file, shipped with xine-lib, PulseAudio and the LScube projects, is simply shared by copying it out of the source distribution or repositories.

When using external macro files to store custom and generic macros (which is, most of the time, the suggested approach), you have to tell autoconf where to look for them. Many different approaches are available for this task, and this guide will try to explain most, if not all, of them.

Note

While there is no functional requirement for that, the guide will assume that all your macro files are inside the m4/ directory; this is the most common directory used to keep the macro files, and for the principle of least surprise, you probably want to also put yours there.

Some projects use other directory names (autoconf/, ac-macros/, …) but this often adds more work for the distributors packaging or fixing the software, since they have to check where to find the macros.

6.1.1. With Just autoconf

When not using automake, and just relying on autoconf, the macro files are not picked up by default.

Indeed, if you just added your testing macro in the configure.ac file, you'll be finding it just copied over in the final configure:

% cat m4/test.m4
AC_DEFUN([AUTOTOOLS_MYTHBUSTER], [
  AC_MSG_CHECKING([testing])
  AC_MSG_RESULT([ok])
])
% fgrep AUTOTOOLS_MYTHBUSTER configure.ac
AUTOTOOLS_MYTHBUSTER()
% fgrep AUTOTOOLS_MYTHBUSTER configure
AUTOTOOLS_MYTHBUSTER()

Indeed, what you have to do is to force the actual inclusion of the macro file in the configure.ac file.

Example 1.5. Including an External Macro File without automake

AC_INIT

m4_include([m4/autotools_mythbuster.m4])

AUTOTOOLS_MYTHBUSTER

The m4_include directive works quite like the #include directive of the C programming language, and simply copies over the content of the file.

To not include comments starting with # in the generated configure script call the m4_include before the AC_INIT.


The only file that is read by autoconf other than the configure.ac file is the aclocal.m4 file. This file is often managed with the aclocal utility that ships with automake, so it's really suggested not to make use of it manually.

6.1.1.1. What About -I m4?

The autoconf tool has a parameter -I that allows adding a directory to the search path for the conversion. This command is also not used to discover macro files.

What it is useful for is to avoid using the full path name of a macro file, letting it be picked up either from the system or from the local directory (giving priority to the system copy).

AC_INIT

m4_include([pkg.m4])

PKG_PROG_PKG_CONFIG

In this case, the macro file is included with the generic base name value of pkg.m4 instead of m4/pkg.m4. If the macro file is available to the system (in /usr/share/autoconf for instance) the macro will be picked up from there; otherwise, if autoconf -I m4 is used, the one in the m4 directory will be used.

6.1.2. Using AC_CONFIG_MACRO_DIR (and aclocal)

Starting from version 2.58, autoconf provide the macro AC_CONFIG_MACRO_DIR to declare where additional macro files are to be put and found. The argument passed to this macro is commonly m4.

This macro, for the longest time, has been used only by libtool starting from version 2.0, to identify where to copy its own macro files when using libtoolize --copy.

Starting from version 1.13, automake augments autoconf with a macro called AC_CONFIG_MACRO_DIRS, that provides a space-separated list of directories to use for looking up m4 files. The same macro will be available as part of autoconf 2.70.

The list of directories declared in these macros will be used by the aclocal tool to look up the macros called by the configure.ac file. After all the macros (and their dependencies) have been gathered, it will create a aclocal.m4 file that autoconf will use.

% cat configure.ac
AC_INIT

PKG_PROG_PKG_CONFIG

% aclocal
% ls -l aclocal.m4
-rw-r--r-- 1 flame flame 5775 2009-08-06 10:17 aclocal.m4

% fgrep PKG_PROG_PKG_CONFIG aclocal.m4 | grep AC_DEFUN
AC_DEFUN([PKG_PROG_PKG_CONFIG],

% autoconf
% ./configure
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes

In contrast to what autoconf does, aclocal takes its macro files from the /usr/share/aclocal path, where most software installs them, and copies the macro files where they are defined directly inside aclocal.m4, appending them to one another. Then autoconf reads the file as if it was part of its macros' library.

Local macros will also be looked up, but their content will not be appended to aclocal.m4. Instead, it will use the m4_include directive, to include the local file.

The search path for local files, as of version 1.13 of automake, is defined by the directories listed in AC_CONFIG_MACRO_DIR and AC_CONFIG_MACRO_DIRS arguments. Previously, it was common to use a variable defined in Makefile.am (ACLOCAL_AMFLAGS) to pass extra parameters to aclocal. This behaviour is deprecated and will soon not be supported.

% cat configure.ac
AC_INIT

AC_CONFIG_MACRO_DIR([m4])

AUTOTOOLS_MYTHBUSTER
% aclocal
% cat aclocal.m4
# generated automatically by aclocal 1.13 -*- Autoconf -*-

dnl […] snip […]

m4_include([m4/autotools_mythbuster.m4])

% autoconf
% ./configure
checking testing... ok
6.1.2.1. The acinclude.m4 file.

In addition to searching its own directory and the include path given on the command line, the aclocal tool takes into consideration another file: acinclude.m4. This file is also copied (rather than included) in the final output of the tool, and then picked up by autoconf.

This file is often used to put together multiple macros from different macro files, without having to use an m4/ directory or equivalent. This usage is discouraged by this guide, because it often leads to overly long files, with no logical distinction between macros.

Once again, this has to be considered an old interface kept for compatibility; the m4/ macro directory with its macro files is the suggested method of adding new macros to a project.

6.2. Once-Expansion

Since macro calls are expanded inline, multiple calls to the same macro will cause more code to be emitted in the final configure script. In turn, this will require a longer time to execute the configure phase, both because more code is to be executed, and because bash gets easily slowed by long scripts.

To solve this problem, a subset of macros can be called through the so-called “Once-Expansion”. Such a macro is usually immune to most of the changes in the current environment, so that the place in the configure script where it is called is not important for the successful completion of the configure phase.

Of course, this comes with a price: once macros might not be called conditionally, and they lack configurable side effects on success or failure (they can have standard side effects like setting variables and cache values, and generating definitions).

To create a once macro, you just define it almost normally, but using the AC_DEFUN_ONCE definition macro. A macro created this way should not make use of parameters that can change between calls; it either has to take parameters used to identify the project or the options to enable (think AC_INIT) or none at all.

6.2.1. Once-expanded checks

Similarly to once-expanded macros, recent autoconf versions provide the so-called “once-expanded checks” for functions, headers, declarations, …

The use of these macros is slightly different from the standard checks, since they follow, for the most part, the same rules as once-expanded macros: with the exclusion of the parameter with the list of elements to check for, there can be no parameters executing side-effects or changing the default behaviour.

For instance when checking for a series of headers with once-expansion, you'd just write it as this:

    AC_CHECK_HEADERS_ONCE([header1.h header2.h header3.h])
    

In this case you cannot stop when the first of these is found, you cannot error out when one is not found either, and finally you cannot pass further headers, not even to fix problems with headers present that cannot be compiled.

Like once-expanded macros, once-expanded checks are expanded as early as possible, bundled together, and at most one time. This reduces the amount of code generated, especially if multiple code paths would check for the same header multiple times.