23.3.5 Macro interface
When designing your macro, it is worth spending some time deciding on
what your macro's interface--the macro's name and argument list--will
be. Often, it will be possible to extract general purpose
functionality into a generic macro and to write a second macro which is
a client of the generic one. Like planning the prototype for a C
function, this is usually a straightforward process of deciding what
arguments are required by the macro to perform its function. However,
there are a couple of further considerations and they are discussed
M4 macros refer to their arguments by number with a syntax such
$1. It is typically more difficult to read an M4 macro
definition and understand what each argument's designation is than in a
C function body, where the formal argument is referred to by its name.
Therefore, it's a good idea to include a standard comment block above
each macro that documents the macro and gives an indication of what each
argument is for. Here is an example from the Autoconf source code:
# AC_CHECK_FILE(FILE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# Check for the existence of FILE.
To remain general purpose, the existing Autoconf macros follow the
convention of keeping side-effects outside the definition of the macro.
Here, when a user invokes `AC_CHECK_FILE', they must provide shell
code to implement the side effect that they want to occur if the
`FILE' is found or is not found. Some macros implement a basic and
desirable action like defining a symbol like `HAVE_UNISTD_H' if no
user-defined actions are provided. In general, your macros should
provide an interface which is consistent with the interfaces provided by
the core Autoconf macros.
M4 macros may have variable argument lists, so it is possible to
implement macros which have defaults for arguments. By testing each
individual argument against the empty string with `ifelse', it is
possible for users to accept the default behavior for individual
arguments by passing empty values:
[AC_MSG_ERROR([something is really wrong])])
One final point to consider when designing the interface for a macro is
how to handle macros that are generic in nature and, say, wish to set a
cache variable whose name is based on one of the arguments. Consider
the `AC_CHECK_HEADER' macro--it defines a symbol and makes an entry
in the cache that reflects the result of the test it performs.
`AC_CHECK_HEADER' takes an argument -- namely the name of a header
file to look for. This macro cannot just make a cache entry with a name
ac_cv_check_header, since it would only work once; any
further uses of this macro in `configure.in' would cause an
incorrect result to be drawn from the cache. Instead, the name of the
symbol that is defined and the name of the cache variable that is set
need to be computed from one of the arguments: the name of the header
file being sought. What we really need is to define
HAVE_UNISTD_H and set the cache variable
ac_cv_header_unistd_h. This can be achieved with some
tr magic in the macro which transforms the filename into
uppercase characters for the call to
AC_DEFINE and into lowercase
for the cache variable name. Unknown characters such as `.' need
to be transformed into underscores.
Some existing macros also allow the user to pass in the name of a cache
variable name so that the macro does not need to compute a name. In
general, this should be avoided, as it makes the macro harder to use and
exposes details of the caching system to the user.