GNU Make Escaping: A Walk on the Wild Side

[article]
Summary:

Sometimes you find yourself needing to insert a special character in a Makefile: perhaps you need a newline inside a $(error) message, or a space character in a $(subst) or a comma as the argument to a GNU Make function.  Those three simple things can be frustratingly hard in GNU Make; this article takes you through simple GNU Make syntax that removes the frustration.

Sometimes you find yourself needing to insert a special character in a Makefile: perhaps you need a newline inside a $(error) message, or a space character in a $(subst) or a comma as the argument to a GNU Make function.  Those three simple things can be frustratingly hard in GNU Make; this article takes you through simple GNU Make syntax that removes the frustration.

GNU Make's escaping rules
GNU Make's handling of 'tab' as the start of a command is a legendary language feature, but some other special characters can trip you up.  GNU Make's handling of $, %, ?, *, [, ~, \, and # are all special.

Every GNU Make user is familiar with $ for starting a macro reference.  It's possible to write $(macro) or ${macro} to get the value of macro and if the macro name is a single character (such as a) then the parens can be dropped and the short hand $a used.

To get a literal $ you write $$.  So to define a macro containing a single $ symbol you'd write:

dollar := $$

The % character rears its ugly head in three different places: in the vpath directive, in a $(patsubst) and in a pattern or static-pattern rule.

Escaping % is not as simple as $, but it only needs to be done in the three situation above, and the same rules apply for each.

The three rules for % escaping are:

1. % can be escaped with a single \ character (i.e. \% becomes a literal %.

2. If you need to put a literal \ in front of a % (i.e. you want the \ to not escape the %) then escape it with \ (i.e. \\% becomes a literal \ followed by a % character that will be used for the pattern match).

3. Don't worry about escaping \ anywhere else in a pattern, it will be treated as literal (i.e. \hello is \hello).

?, *, [, and ] get treated specially when they appear in a filename.  A Makefile that does

*.c:

    @command

Will actually search for all .c files in the current directory and define a rule for each.  The target (and the same applies for prerequisites and files mentioned in the include
directive) are globbed if they contain a wildcard character.  The globbing characters have the same meaning as in the Bourne shell.

The ~ character is also handled specially in filenames and is expanded to the home directory of the current user.

All of those special filename characters can be escaped with a \.  The following Makefile defines a rule for the file named literally *.c.

\*.c:

    @command

As well as the escaping function mentioned in this section, the \ can also be used as an continuation character at the end of a line:

all: \

prerequisite \

something else

    @command

The # character is used to start a comment and it can be made literal with a \ escape:

pound := \#

I just want a newline!

GNU Make does its best to insulate you from the newline character.  You can't escape a newline, there's no syntax for special characters (e.g. you can't write \n), and even the $(shell) function strips newlines from the returned value.

But you can define a macro that contains a newline using the define syntax:

define newline

endef

(Note that there are two blanks lines in the definition above).  With that definition $(newline) will expand to a newline and it can be used to format an error message nicely:

$(error This is an error message$(newline)with two lines)

Because of GNU Make's rather liberal macro naming

About the author

CMCrossroads is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.