GNU Make path handling

[article]

that would work with a different separator.   One way to do that is to define a variable called / (GNU Make lets you get away using almost anything as a variable name) and use it in place of /.

/ := /
SRCDIR := src
MODULE_DIR := module_1
MODULE_SRCS := $(SRCDIR)$/$(MODULE_DIR)

Of course, if that makes you uncomfortable just call is SEP:

SEP := /
SRCDIR := src
MODULE_DIR := module_1
MODULE_SRCS := $(SRCDIR)$(SEP)$(MODULE_DIR)

Now when switching to Windows you can just redefine / or SEP to \.  I use $(strip) to define / because it's hard to get a literal \ on its own (since GNU Make interprets it as a line continuation and it can't be escaped).

/ := $(strip \)
SRCDIR := src
MODULE_DIR := module_1
MODULE_SRCS := $(SRCDIR)$/$(MODULE_DIR)

Note, however, that the Windows builds of GNU Make will also accept / as a path separator, so paths like c:/src are legal.  Using those paths will simplify the Makefile but be careful when passing them to a native Windows tool that expects \ separaed paths.   If that's necessary then the follwing simple function will convert a forward slash path to a back slash path:

forward-to-backward = $(subst /,\,$1)

A Windows oddity: case insensitive but case preserving On POSIX systems file names as case sensitive, on Windows they are not.  On Windows the files File, file and FILE are all the same physical file.  But Windows also has the oddity that the first time a file is accessed the specific case used is recorded and preserved.  Thus if we touch File it will appear as File in the file system (but can be accessed as FILE, file or any other combination of case).

By default GNU Make does case sensitive target comparisons and thus the following Makefile does not do what you might expect:

.PHONY: all
all: File
file:
    @touch $@

It is possible to compile GNU Make on Windows to do case insensitive comparisons (with the HAVE_CASE_INSENSITIVE_FS option).

This oddity is more likely to arise when a target is specified in a Makefile and also found using a wildcard search.  The target names may differ in case and that may cause an unexpected 'No rule to make' error.

GNU Make built in path functions and macros
It's possible to find out the current working directory in GNU Make using the built in CURDIR.  Note that CURDIR will follow symlinks so suppose you are in /foo but /foo is actually a symlink to /somewhwere/foo.   CURDIR will report the directory as /somewhere/foo.  If you need the non-symlink-followed directory name then call pwd via $(shell):

CURRENT_DIRECTORY := $(shell pwd)

The other directory that it's often interesting to find is the directory in which the current Makefile is stored.  This can be done using the MAKEFILE_LIST macro that was introduced in GNU Make 3.80.   At the start of a Makefile it's possible to extract its directory as follows:

CURRENT_MAKEFILE := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
MAKEFILE_DIRECTORY := $(dir $(CURRENT_MAKEFILE))

GNU Make has functions for splitting paths into components: dir, notdir, basename and suffix.

Consider a file name /foo/bar/source.c stored in the macro FILE.   The four functions above can be used to extract the directory, file name and suffix:

Function Result
dir /foo/bar/
notdir source.c
basename source
suffix .c

You can see that the directory, the non-directory part, the suffix (or extension) and the non-directory part without the suffix have been extracted.   These four functions make file name manipulation easy.   If there was no directory specified then GNU Make assumes ./.  For example, suppose that FILE was just source.c:

Function Result
dir ./
notdir source.c
basename source
suffix .c

Since these functions

About the author

AgileConnection is one of the growing communities of the TechWell network.

Featuring fresh, insightful stories, TechWell.com is the place to go for what is happening in software development and delivery.  Join the conversation now!