[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

21.4 Features of M4

M4 includes a number of pre-defined macros that make it a powerful preprocessor. We will take a tour of the most important features provided by these macros. Although some of these features are not very relevant to GNU Autotools users, Autoconf is implemented using most of them. For this reason, it is useful to understand the features to better understand Autoconf’s behavior and for debugging your own ‘configure’ scripts.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

21.4.1 Discarding input

A macro called dnl discards text from the input. The dnl macro takes no arguments and expands to the empty string, but it has the side effect of discarding all input up to and including the next newline character. Here is an example of dnl from the Autoconf source code:

 
# AC_LANG_POP
# -----------
# Restore the previous language.
define([AC_LANG_POP],
[popdef([_AC_LANG])dnl
ifelse(_AC_LANG, [_AC_LANG],
        [AC_FATAL([too many $0])])dnl
AC_LANG(_AC_LANG)])

It is important to remember dnl’s behavior: it discards the newline character, which can have unexpected effects on generated ‘configure’ scripts! If you want a newline to appear in the output, you must add an extra blank line to compensate.

dnl need not appear in the first column of a given line – it will begin discarding input at any point that it is invoked in the input file. However, be aware of the newline eating problem again! In the example of AC_TRY_LINK_FUNC above, note the deliberate use of dnl to remove surplus newline characters.

In general, dnl makes sense for macro invocations that appear on a single line, where you would expect the whole line to simply vanish from the output. In the following subsections, dnl will be used to illustrate where it makes sense to use it.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

21.4.2 Macro management

A number of built-in macros exist in M4 to manage macros. We shall examine the most common ones that you’re likely to encounter. There are others and you should consult the GNU M4 manual for further information.

The most obvious one is define, which defines a macro. It expands to the empty string:

 
define([foo], [bar])dnl
define([combine], [$1 and $2])dnl

It is worth highlighting again the liberal use of quoting. We wish to define a pair of macros whose names are literally foo and combine. If another macro had been previously defined with either of these names, m4 would have expanded the macro immediately and passed the expansion of foo to define, giving unexpected results.

The undefine macro will remove a macro’s definition from M4’s macro table. It also expands to the empty string:

 
undefine([foo])dnl
undefine([combine])dnl

Recall that once removed from the macro table, unmatched text will once more be passed through to the output.

The defn macro expands to the definition of a macro, named by the single argument to defn. It is quoted, so that it can be used as the body of a new, renamed macro:

 
define([newbie], defn([foo]))dnl
undefine([foo])dnl

The ifdef macro can be used to determine if a macro name has an existing definition. If it does exist, ifdef expands to the second argument, otherwise it expands to the third:

 
ifdef([foo], [yes], [no])dnl

Again, yes and no have been quoted to prevent expansion due to any pre-existing macros with those names. Always consider this a real possibility!

Finally, a word about built-in macros: these macros are all defined for you when m4 is started. One common problem with these macros is that they are not in any kind of name space, so it’s easier to accidentally invoke them or want to define a macro with an existing name. One solution is to use the define and defn combination shown above to rename all of the macros, one by one. This is how Autoconf makes the distinction clear.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

21.4.3 Conditionals

Macros which can expand to different strings based on runtime tests are extremely useful–they are used extensively throughout macros in GNU Autotools and third party macros. The macro that we will examine closely is ifelse. This macro compares two strings and expands to a different string based on the result of the comparison. The first form of ifelse is akin to the if/then/else construct in other programming languages:

 
ifelse(string1, string2, equal, not-equal)

The other form is unusual to a beginner because it actually resembles a case statement from other programming languages:

 
ifelse(string1, string2, equala, string3, string4, equalb, default)

If ‘string1’ and ‘string2’ are equal, this macro expands to ‘equala’. If they are not equal, m4 will shift the argument list three positions to the left and try again:

 
ifelse(string3, string4, equalb, default)

If ‘string3’ and ‘string4’ are equal, this macro expands to ‘equalb’. If they are not equal, it expands to ‘default’. The number of cases that may be in the argument list is unbounded.

As it has been mentioned in Macros and macro expansion, macros that accept arguments may access their arguments through specially named macros like ‘$1’. If a macro has been defined, no checking of argument counts is performed before it is expanded and the macro may examine the number of arguments given through the ‘$#’ macro. This has a useful result: you may invoke a macro with too few (or too many) arguments and the macro will still be expanded. In the example below, ‘$2’ will expand to the empty string.

 
define([foo], [$1 and $2])dnl
foo([a])
⇒a and

This is useful because m4 will expand the macro and give the macro the opportunity to test each argument for the empty string. In effect, we have the equivalent of default arguments from other programming languages. The macro can use ifelse to provide a default value if, say, ‘$2’ is the empty string. You will notice in much of the documentation for existing Autoconf macros that arguments may be left blank to accept the default value. This is an important idiom that you should practice in your own macros.

In this example, we wish to accept the default shell code fragment for the case where ‘/etc/passwd’ is found in the build system’s file system, but output ‘Big trouble!’ if it is not.

 
AC_CHECK_FILE([/etc/passwd], [], [echo "Big trouble!"])

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

21.4.4 Looping

There is no support in M4 for doing traditional iterations (ie. ‘for-do’ loops), however macros may invoke themselves. Thus, it is possible to iterate using recursion. The recursive definition can use conditionals (Conditionals) to terminate the loop at its completion by providing a trivial case. The GNU M4 manual provides some clever recursive definitions, including a definition for a forloop macro that emulates a ‘for-do’ loop.

It is conceivable that you might wish to use these M4 constructs when writing macros to generate large amounts of in-line shell code or arbitrarily nested if; then; fi statements.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

21.4.5 Diversions

Diversions are a facility in M4 for diverting text from the input stream into a holding buffer. There is a large number of diversion buffers in GNU M4, limited only by available memory. Text can be diverted into any one of these buffers and then ‘undiverted’ back to the output (diversion number 0) at a later stage.

Text is diverted and undiverted using the divert and undivert macros. They expand to the empty string, with the side effect of setting the diversion. Here is an illustrative example:

 
divert(1)dnl
This goes at the end.
divert(0)dnl
This goes at the beginning.
undivert(1)dnl
⇒This goes at the beginning.
⇒This goes at the end.

It is unlikely that you will want to use diversions in your own macros, and it is difficult to do reliably without understanding the internals of Autoconf. However, it is interesting to note that this is how autoconf generates fragments of shell code on-the-fly that must precede shell code at the current point in the ‘configure’ script.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

21.4.6 Including files

M4 permits you to include files into the input stream using the include and sinclude macros. They simply expand to the contents of the named file. Of course, the expansion will be rescanned as the normal rules dictate (Fundamentals of M4 processing).

The difference between include and sinclude is subtle: if the filename given as an argument to include is not present, an error will be raised. The sinclude macro will instead expand to the empty string—presumably the ‘s’ stands for ‘silent’.

Older GNU Autotools macros that tried to be modular would use the include and sinclude macros to import libraries of macros from other sources. While this is still a workable mechanism, there is an active effort within the GNU Autotools development community to improve the packaging system for macros. An ‘--install’ option is being developed to improve the mechanism for importing macros from a library.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Ben Elliston on July 10, 2015 using texi2html 1.82.