Programming Utilities Guide

Overview

m4 is a general-purpose macro processor that can be used to preprocess C and assembly language programs. Besides the straightforward replacement of one string of text by another, m4 enables you to perform

You can use built-in macros to perform these tasks or you can define your own macros. Built-in and user-defined macros work exactly the same way except that some of the built-in macros have side effects on the state of the process.

The basic operation of m4 is to read every alphanumeric token (string of letters and digits) and determine if the token is the name of a macro. The name of the macro is replaced by its defining text, and the resulting string is replaced onto the input to be rescanned. Macros can be called with arguments. The arguments are collected and substituted into the right places in the defining text before the defining text is rescanned.

Macro calls have the general form:

name(arg1, arg2, ..., argn)

If a macro name is not immediately followed by a left parenthesis, it is assumed to have no arguments. Leading unquoted blanks, tabs, and newlines are ignored while collecting arguments. Left and right single quotes are used to quote strings. The value of a quoted string is the string stripped of the quotes.

When a macro name is recognized, its arguments are collected by searching for a matching right parenthesis. If fewer arguments are supplied than are in the macro definition, the trailing arguments are taken to be null. Macro evaluation proceeds normally during the collection of the arguments, and any commas or right parentheses that appear in the value of a nested call are as effective as those in the original input text. After argument collection, the value of the macro is returned to the input stream and rescanned. This is explained in the following paragraphs.

You invoke m4 with a command of the form

$ m4 file file file

Each argument file is processed in order. If there are no arguments or if an argument is a hyphen, the standard input is read. If you are eventually going to compile the m4 output, use a command like this:

$ m4 file1.m4 > file1.c

You can use the -D option to define a macro on the m4 command line. Suppose you have two similar versions of a program. You might have a single m4 input file capable of generating the two output files. That is, file1.m4 could contain lines such as:

if(VER, 1, do_something) 
if(VER, 2, do_something)

Your makefile for the program might look like this:

file1.1.c : file1.m4 
m4 -DVER=1 file1.m4 > file1.1.c 
...  
file1.2.c : file1.m4 
m4 -DVER=2 file1.m4 > file1.2.c 
...  

You can use the -U option to ``undefine'' VER. If file1.m4 contains

if(VER, 1, do_something) 
if(VER, 2, do_something) 
ifndef(VER, do_something)

then your makefile would contain

file0.0.c : file1.m4 
m4 -UVER file1.m4 > file1.0.c 
...  
file1.1.c : file1.m4 
m4 -DVER=1 file1.m4 > file1.1.c 
...  
file1.2.c : file1.m4 
m4 -DVER=2 file1.m4 > file1.2.c 
...