Next: , Previous: Diagnostic Macros, Up: Programming in M4sugar


8.3.3 Diversion support

M4sugar makes heavy use of diversions under the hood, because it is often the case that text that must appear early in the output is not discovered until late in the input. Additionally, some of the topological sorting algorithms used in resolving macro dependencies use diversions. However, most macros should not need to change diversions directly, but rather rely on higher-level M4sugar macros to manage diversions transparently. If you change diversions improperly, you risk generating a syntactically invalid script, because an incorrect diversion will violate assumptions made by many macros about whether prerequisite text has been previously output. In short, if you manually change the diversion, you should not expect any macros provided by the Autoconf package to work until you have restored the diversion stack back to its original state.

In the rare case that it is necessary to write a macro that explicitly outputs text to a different diversion, it is important to be aware of an M4 limitation regarding diversions: text only goes to a diversion if it is not part of argument collection. Therefore, any macro that changes the current diversion cannot be used as an unquoted argument to another macro, but must be expanded at the top level. The macro m4_expand will diagnose any attempt to change diversions, since it is generally useful only as an argument to another macro. The following example shows what happens when diversion manipulation is attempted within macro arguments:

     m4_do([normal text]
     m4_divert_push([KILL])unwanted[]m4_divert_pop([KILL])
     [m4_divert_push([KILL])discarded[]m4_divert_pop([KILL])])dnl
     ⇒normal text
     ⇒unwanted

Notice that the unquoted text unwanted is output, even though it was processed while the current diversion was KILL, because it was collected as part of the argument to m4_do. However, the text discarded disappeared as desired, because the diversion changes were single-quoted, and were not expanded until the top-level rescan of the output of m4_do.

To make diversion management easier, M4sugar uses the concept of named diversions. Rather than using diversion numbers directly, it is nicer to associate a name with each diversion. The diversion number associated with a particular diversion name is an implementation detail, and a syntax warning is issued if a diversion number is used instead of a name. In general, you should not output text to a named diversion until after calling the appropriate initialization routine for your language (m4_init, AS_INIT, AT_INIT, ...), although there are some exceptions documented below.

M4sugar defines two named diversions.

KILL
Text written to this diversion is discarded. This is the default diversion once M4sugar is initialized.
GROW
This diversion is used behind the scenes by topological sorting macros, such as AC_REQUIRE.

M4sh adds several more named diversions.

BINSH
This diversion is reserved for the ‘#!’ interpreter line.
HEADER-REVISION
This diversion holds text from AC_REVISION.
HEADER-COMMENT
This diversion holds comments about the purpose of a file.
HEADER-COPYRIGHT
This diversion is managed by AC_COPYRIGHT.
M4SH-SANITIZE
This diversion contains M4sh sanitization code, used to ensure M4sh is executing in a reasonable shell environment.
M4SH-INIT
This diversion contains M4sh initialization code, initializing variables that are required by other M4sh macros.
BODY
This diversion contains the body of the shell code, and is the default diversion once M4sh is initialized.

Autotest inherits diversions from M4sh, and changes the default diversion from BODY back to KILL. It also adds several more named diversions, with the following subset designed for developer use.

PREPARE_TESTS
This diversion contains initialization sequences which are executed after atconfig and atlocal, and after all command line arguments have been parsed, but prior to running any tests. It can be used to set up state that is required across all tests. This diversion will work even before AT_INIT.

Autoconf inherits diversions from M4sh, and adds the following named diversions which developers can utilize.

DEFAULTS
This diversion contains shell variable assignments to set defaults that must be in place before arguments are parsed. This diversion is placed early enough in configure that it is unsafe to expand any autoconf macros into this diversion.
HELP_ENABLE
If AC_PRESERVE_HELP_ORDER was used, then text placed in this diversion will be included as part of a quoted here-doc providing all of the --help output of configure related to options created by AC_ARG_WITH and AC_ARG_ENABLE.
INIT_PREPARE
This diversion occurs after all command line options have been parsed, but prior to the main body of the configure script. This diversion is the last chance to insert shell code such as variable assignments or shell function declarations that will used by the expansion of other macros.

For now, the remaining named diversions of Autoconf, Autoheader, and Autotest are not documented. In other words, intentionally outputting text into an undocumented diversion is subject to breakage in a future release of Autoconf.

— Macro: m4_cleardivert (diversion...)

Permanently discard any text that has been diverted into diversion.

— Macro: m4_divert_once (diversion, [content])

Similar to m4_divert_text, except that content is only output to diversion if this is the first time that m4_divert_once has been called with its particular arguments.

— Macro: m4_divert_pop ([diversion])

If provided, check that the current diversion is indeed diversion. Then change to the diversion located earlier on the stack, giving an error if an attempt is made to pop beyond the initial m4sugar diversion of KILL.

— Macro: m4_divert_push (diversion)

Remember the former diversion on the diversion stack, and output subsequent text into diversion. M4sugar maintains a diversion stack, and issues an error if there is not a matching pop for every push.

— Macro: m4_divert_text (diversion, [content])

Output content and a newline into diversion, without affecting the current diversion. Shorthand for:

          m4_divert_push([diversion])content
          m4_divert_pop([diversion])dnl

One use of m4_divert_text is to develop two related macros, where macro ‘MY_A’ does the work, but adjusts what work is performed based on whether the optional macro ‘MY_B’ has also been expanded. Of course, it is possible to use AC_BEFORE within MY_A to require that ‘MY_B’ occurs first, if it occurs at all. But this imposes an ordering restriction on the user; it would be nicer if macros ‘MY_A’ and ‘MY_B’ can be invoked in either order. The trick is to let ‘MY_B’ leave a breadcrumb in an early diversion, which ‘MY_A’ can then use to determine whether ‘MY_B’ has been expanded.

          AC_DEFUN([MY_A],
          [# various actions
          if test -n "$b_was_used"; then
            # extra action
          fi])
          AC_DEFUN([MY_B],
          [AC_REQUIRE([MY_A])dnl
          m4_divert_text([INIT_PREPARE], [b_was_used=true])])
— Macro: m4_init

Initialize the M4sugar environment, setting up the default named diversion to be KILL.