GNU Make meets file names with spaces in them


Suppose you are faced with creating a Makefile that needs to deal with two files named foo bar and bar baz, with foo bar built from bar ba'.  I've used italics to make clear that these are file names that include spaces.

A Simple Example

Suppose you are faced with creating a Makefile that needs to deal with two files named  foo bar and bar baz , with  foo bar  built from  bar ba '.  I've used  italics to make clear that these are file names that include spaces.

A naive way to write this in a Makefile would be:

foo bar: bar baz

    @echo Making $@ from $<

That doesn't work at all.  GNU Make can't differentiate between the cases where the spaces there are part of, or not part of, the file names.  In fact the Makefile above is exactly
the same as:

foo: bar baz

    @echo Making $@ from $<

bar: bar baz

    @echo Making $@ from $<

Placing quotations marks around the file names doesn't work.  If you try to do:

"foo bar": "bar baz"

    @echo Making $@ from $<

then GNU Make thinks you are talking about four files called "foo, bar", "bar and baz". 
GNU Make has totally ignored the double-quotes and split the list of file names on spaces.

One way: escape the spaces with \\

GNU Make does have an escaping operator, \\ which can be used to escape sensitive
characters (such as a literal # that musn't start a comment, or a literal % in a pattern
that shouldn't be the wildcard character). 

In a file name in a rule \\ can be used to escape a space.  The example Makefile can be
rewritten as follows:

foo\\ bar: bar\\ baz

    @echo Making $@ from $<

and it will work correctly.  The \\ is removed during the parsing of the Makefile, but the
actual target and prerequisite names correctly contain spaces.   This will be reflected in
the automatic variables (such as $@). 

When foo bar needs updating the simple Makefile will output:

Making foo bar from bar baz

The same escaping mechanism can also be used inside GNU Make's $(wildcard) function.   To
check for the existence of foo bar you can do $(wildcard foo\\ bar) and GNU Make will
treat foo bar as a single file name to look for in the file system.

Unfortunately, GNU Make's other functions that deal with space-separated list do not
respect the escaping of the space.  So, for example the output of $(sort foo\\ bar) is the
list bar foo\\ and not foo\\ bar as you might expect.

The following table shows the GNU Make functions that accept a list as an argument and
whether they respect escaping of spaces.

Function Respect \\
addprefix No
addsuffix No
basename No
dir No
filter No
filter-out No
firstword No
foreach No
join No
notdir No
patsubst No
sort No
suffix No
word No
wordlist No
words No
wildcard Yes

So, $(wildcard) is the lone hold out.

This leads to a problem if you have to deal with the automatic variables that contain
lists of targets.  Consider this slightly more complicated example Makefile:

foo\\ bar: bar\\ baz a\\ b

    @echo Making $@ from $<

Now foo bar has two prerequisites bar baz and a b.  What's the value of $^ (the list of
all prerequisites) in this case?  It's bar baz a b: the escaping is gone, and even if it
weren't gone the table above shows that it would be pretty much useless anyway.  $^ is,
from GNU Make's perspective, a list with four elements.

A quick look at the definitions of the automatic variables tells use which are safe to use
in the presence of spaces in file names:

Automatic Variable Safe?
$@ Yes
$< Yes
$% Yes

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.