[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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.