GNU Make path handling


Ask Mr. Make discusses how GNU Make handles paths.

The Basics: Target name matching

Take a look at the following example Makefile and suppose that ../foo is missing.  Does the Makefile manage to create it?

.PHONY: all
all: ../foo
    touch $@

If you run that Makefile with GNU Make you might be surprised to see the error

make: *** No rule to make target `../foo', needed by `all'.  Stop.

Now if you change the Makefile to:

.PHONY: all
all: ../foo
touch $@

you'll find that it works as expected and performs a touch ../foo.

The first Makefile fails because GNU Make doesn't do path manipulation in target names and so it sees two different targets called ../foo and .././foo and fails to make the connection between the two.   The second Makefile works because I lied in the last sentence. GNU Make does do a tiny big of path manipulation: it will strip leading ./ from target names.   So in the second Makefile both targets are ../foo and it works as expected.

In general the rule with GNU Make targets is that they are treated as literal strings without interpreting them in any way.   That means it's essential that when referring to a target in a Makefile you always make sure that the same string is used.

The Basics: Lists of paths
It bears repeating that GNU Make lists are just strings where any whitespace is considered to be the list seperator.  That means that paths with spaces in them are not recommended because it makes using many of GNU Make's built in functions impossible, and spaces in paths cause problems with targets. 

For example, suppose a target is /tmp/sub directory/target and we write a rule for it like this:

/tmp/sub directory/target:
    @do stuff

GNU Make will actually interpret that as two rules, one for /tmp/sub and one for directory/target, just as if you'd written

    @do stuff
    @do stuff

You can work around that by escaping that space with \ but that escape is poorly  respected by GNU Make (it only works in target names and the $(wildcard) function).  

Unless you have to, avoid spaces in target names.

The Basics: Lists of paths in VPATH and vpath
Another place that lists of paths appear in GNU Make is when specifying the VPATH or in a vpath directive.   For example, it's possible to set the VPATH to search for source files to a list of : or whitespace separated paths:

VPATH = ../src:../thirdparty/src /src
vpath %c ../src:../thirdparty/src /src

GNU Make will split that path correctly at either colons or whitespaces.  On Windows system that native builds of GNU Make use ; as the path separator for VPATH (and vpath) because : is needed for drive letters.   In these paths GNU Make on Windows actually tries to be smart and will split on colons unless it looks like a drive letter (one letter followed by a colon).   This drive letter intelligence actually creates a problem if you have a directory
in the path whose name is a single letter: in that case you must use ; as the path separator otherwise GNU Make will think it's a drive.

VPATH = ../src;../thirdparty/src /src
vpath %c ../src;../thirdparty/src /src

On both POSIX and Windows systems a space in a path is a separator in a VPATH and vpath.   So the space is the best bet for cross-platform GNU Makeing.

/ or \

On POSIX systems / is the path separator and on Windows systems it's \.   It's common to see paths being built up in Makefiles like this:

SRCDIR := src

MODULE_DIR := module_1


It would be nice to remove the POSIX-only / there are replace it with something

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.