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

7. How to debug macros and input

When writing macros for m4, they often do not work as intended on the first try (as is the case with most programming languages). Fortunately, there is support for macro debugging in m4.


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

7.1 Displaying macro definitions

If you want to see what a name expands into, you can use the builtin dumpdef:

Builtin: dumpdef ([names…]@c)

Accepts any number of arguments. If called without any arguments, it displays the definitions of all known names, otherwise it displays the definitions of the names given. The output is printed to the current debug file (usually standard error), and is sorted by name. If an unknown name is encountered, a warning is printed.

The expansion of dumpdef is void.

 
$ m4 -d
define(`foo', `Hello world.')
⇒
dumpdef(`foo')
error-->foo: @c`Hello world.'
⇒
dumpdef(`define')
error-->define: @c<define>
⇒

The last example shows how builtin macros definitions are displayed. The definition that is dumped corresponds to what would occur if the macro were to be called at that point, even if other definitions are still live due to redefining a macro during argument collection.

 
$ m4 -d
pushdef(`f', ``$0'1')pushdef(`f', ``$0'2')
⇒
f(popdef(`f')dumpdef(`f'))
error-->f: @c"$0'1'
⇒f2
f(popdef(`f')dumpdef(`f'))
error-->m4:stdin:3: undefined macro `f'
⇒f1

See section Controlling debugging output, for information on controlling the details of the display.


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

7.2 Tracing macro calls

It is possible to trace macro calls and expansions through the builtins traceon and traceoff:

Builtin: traceon ([names…]@c)
Builtin: traceoff ([names…]@c)

When called without any arguments, traceon and traceoff will turn tracing on and off, respectively, for all currently defined macros.

When called with arguments, only the macros listed in names are affected, whether or not they are currently defined.

The expansion of traceon and traceoff is void.

Whenever a traced macro is called and the arguments have been collected, the call is displayed. If the expansion of the macro call is not void, the expansion can be displayed after the call. The output is printed to the current debug file (defaulting to standard error, see section Saving debugging output).

 
$ m4 -d
define(`foo', `Hello World.')
⇒
define(`echo', `$@')
⇒
traceon(`foo', `echo')
⇒
foo
error-->m4trace: -1- foo -> `Hello World.'
⇒Hello World.
echo(`gnus', `and gnats')
error-->m4trace: -1- echo(`gnus', `and gnats') -> ``gnus',`and gnats''
⇒gnus,and gnats

The number between dashes is the depth of the expansion. It is one most of the time, signifying an expansion at the outermost level, but it increases when macro arguments contain unquoted macro calls. The maximum number that will appear between dashes is controlled by the option `--nesting-limit' (or `-L', see section Invoking m4). Additionally, the option `--trace' (or `-t') can be used to invoke traceon(name) before parsing input.

 
$ m4 -L 3 -t ifelse
ifelse(`one level')
error-->m4trace: -1- ifelse
⇒
ifelse(ifelse(ifelse(`three levels')))
error-->m4trace: -3- ifelse
error-->m4trace: -2- ifelse
error-->m4trace: -1- ifelse
⇒
ifelse(ifelse(ifelse(ifelse(`four levels'))))
error-->m4:stdin:3: recursion limit of 3 exceeded, use -L<N> to change it

Tracing by name is an attribute that is preserved whether the macro is defined or not. This allows the selection of macros to trace before those macros are defined.

 
$ m4 -d
traceoff(`foo')
⇒
traceon(`foo')
⇒
foo
⇒foo
defn(`foo')
⇒
define(`foo', `bar')
⇒
foo
error-->m4trace: -1- foo -> `bar'
⇒bar
undefine(`foo')
⇒
ifdef(`foo', `yes', `no')
⇒no
indir(`foo')
error-->m4:stdin:9: undefined macro `foo'
⇒
define(`foo', `blah')
⇒
foo
error-->m4trace: -1- foo -> `blah'
⇒blah
traceoff
⇒
foo
⇒blah

Tracing even works on builtins. However, defn (see section Renaming macros) does not transfer tracing status.

 
$ m4 -d
traceon(`traceon')
⇒
traceon(`traceoff')
error-->m4trace: -1- traceon(`traceoff')
⇒
traceoff(`traceoff')
error-->m4trace: -1- traceoff(`traceoff')
⇒
traceoff(`traceon')
⇒
traceon(`eval', `m4_divnum')
⇒
define(`m4_eval', defn(`eval'))
⇒
define(`m4_divnum', defn(`divnum'))
⇒
eval(divnum)
error-->m4trace: -1- eval(`0') -> `0'
⇒0
m4_eval(m4_divnum)
error-->m4trace: -2- m4_divnum -> `0'
⇒0

See section Controlling debugging output, for information on controlling the details of the display. The format of the trace output is not specified by POSIX, and varies between implementations of m4.


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

7.3 Controlling debugging output

The `-d' option to m4 (or `--debug', see section Invoking m4) controls the amount of details presented in three categories of output. Trace output is requested by traceon (see section Tracing macro calls), and each line is prefixed by `m4trace:' in relation to a macro invocation. Debug output tracks useful events not associated with a macro invocation, and each line is prefixed by `m4debug:'. Finally, dumpdef (see section Displaying macro definitions) output is affected, with no prefix added to the output lines.

The flags following the option can be one or more of the following:

a

In trace output, show the actual arguments that were collected before invoking the macro. This applies to all macro calls if the `t' flag is used, otherwise only the macros covered by calls of traceon. Arguments are subject to length truncation specified by the command line option `--arglength' (or `-l').

c

In trace output, show several trace lines for each macro call. A line is shown when the macro is seen, but before the arguments are collected; a second line when the arguments have been collected and a third line after the call has completed.

e

In trace output, show the expansion of each macro call, if it is not void. This applies to all macro calls if the `t' flag is used, otherwise only the macros covered by calls of traceon. The expansion is subject to length truncation specified by the command line option `--arglength' (or `-l').

f

In debug and trace output, include the name of the current input file in the output line.

i

In debug output, print a message each time the current input file is changed.

l

In debug and trace output, include the current input line number in the output line.

p

In debug output, print a message when a named file is found through the path search mechanism (see section Searching for include files), giving the actual file name used.

q

In trace and dumpdef output, quote actual arguments and macro expansions in the display with the current quotes. This is useful in connection with the `a' and `e' flags above.

t

In trace output, trace all macro calls made in this invocation of m4, regardless of the settings of traceon.

x

In trace output, add a unique `macro call id' to each line of the trace output. This is useful in connection with the `c' flag above.

V

A shorthand for all of the above flags.

If no flags are specified with the `-d' option, the default is `aeq'. The examples throughout this manual assume the default flags.

There is a builtin macro debugmode, which allows on-the-fly control of the debugging output format:

Builtin: debugmode ([flags]@c)

The argument flags should be a subset of the letters listed above. As special cases, if the argument starts with a `+', the flags are added to the current debug flags, and if it starts with a `-', they are removed. If no argument is present, all debugging flags are cleared (as if no `-d' was given), and with an empty argument the flags are reset to the default of `aeq'.

The expansion of debugmode is void.

 
$ m4
define(`foo', `FOO')
⇒
traceon(`foo')
⇒
debugmode()
⇒
foo
error-->m4trace: -1- foo -> `FOO'
⇒FOO
debugmode
⇒
foo
error-->m4trace: -1- foo
⇒FOO
debugmode(`+l')
⇒
foo
error-->m4trace:8: -1- foo
⇒FOO

The following example demonstrates the behavior of length truncation, when specified on the command line. Note that each argument and the final result are individually truncated. Also, the special tokens for builtin functions are not truncated.

 
$ m4 -d -l 6
define(`echo', `$@')debugmode(`+t')
⇒
echo(`1', `long string')
error-->m4trace: -1- echo(`1', `long s...') -> ``1',`l...'
⇒1,long string
indir(`echo', defn(`changequote'))
error-->m4trace: -2- defn(`change...')
error-->m4trace: -1- indir(`echo', <changequote>) -> ``''
⇒

This example shows the effects of the debug flags that are not related to macro tracing.

 
$ m4 -dip -I examples
error-->m4debug: input read from stdin
include(`foo')dnl
error-->m4debug: path search for `foo' found `examples/foo'
error-->m4debug: input read from examples/foo
⇒bar
error-->m4debug: input reverted to stdin, line 1
^D
error-->m4debug: input exhausted

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

7.4 Saving debugging output

Debug and tracing output can be redirected to files using either the `--debugfile' option to m4 (see section Invoking m4), or with the builtin macro debugfile:

Builtin: debugfile ([file]@c)

Sends all further debug and trace output to file, opened in append mode. If file is the empty string, debug and trace output are discarded. If debugfile is called without any arguments, debug and trace output are sent to standard error. This does not affect warnings, error messages, or errprint output, which are always sent to standard error. If file cannot be opened, the current debug file is unchanged, and an error is issued.

The expansion of debugfile is void.

 
$ m4 -d
traceon(`divnum')
⇒
divnum(`extra')
error-->m4:stdin:2: Warning: excess arguments to builtin `divnum' ignored
error-->m4trace: -1- divnum(`extra') -> `0'
⇒0
debugfile()
⇒
divnum(`extra')
error-->m4:stdin:4: Warning: excess arguments to builtin `divnum' ignored
⇒0
debugfile
⇒
divnum
error-->m4trace: -1- divnum -> `0'
⇒0

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

This document was generated on July, 20 2009 using texi2html 1.76.