Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Make $(dir) or $(notdir) on a path with spaces

I'm using code similar to the following in a Makefile:

empty:=
space:= $(empty) $(empty)
path_escape = $(subst $(space),\$(space),$(1))

TOP=$(call path_escape,$(abspath .))
TARGET=$(TOP)/foo

$(info TOP='$(TOP)')
$(info TARGET='$(TARGET)')

all: $(TARGET)

$(TARGET):
    touch '$(notdir $@)'

.PHONY: $(TARGET)

If I use this in a directory with no spaces, say space-test, it works fine:

$ make
TOP='/tmp/space-test'
TARGET='/tmp/space-test/foo'
touch 'foo'

However, if I use it in a directory with spaces, say space test, then $(notdir) does the wrong thing:

TOP='/tmp/space\ test'
TARGET='/tmp/space\ test/foo'
touch 'space foo'

What's happening here is that $(notdir) interprets /tmp/space test/foo as two paths and returns the "file part" of both (i.e., space and foo). The weird part of this is that TARGET is properly escaped; somehow, inside the rule or inside $(notdir), the backslash escapes are being ignored.

What am I doing wrong here?

like image 536
Chris Conway Avatar asked Jul 27 '09 18:07

Chris Conway


People also ask

What is Notdir in makefile?

$(notdir names …) Extracts all but the directory-part of each file name in names . If the file name contains no slash, it is left unchanged. Otherwise, everything through the last slash is removed from it.

What is $@ in makefile?

$@ is the name of the target being generated, and $< the first prerequisite (usually a source file). You can find a list of all these special variables in the GNU Make manual.

What is Addprefix in makefile?

$(addprefix prefix,names...) The argument names is regarded as a series of names, separated by whitespace; prefix is used as a unit. The value of prefix is prepended to the front of each individual name and the resulting larger names are concatenated with single spaces between them.


1 Answers

The $(notdir) function in GNU Make takes a list of arguments, separated by spaces. Some functions support escaping spaces with \\, but $(notdir) is not one of them.

This should work:

s? = $(subst $(empty) ,?,$1)
?s = $(subst ?, ,$1)
notdirx = $(call ?s,$(notdir $(call s?,$1)))

$(TARGET):
    touch '$(call notdirx,$@)'

This defines a "space-safe" version of notdir called notdirx. It's quite simple: s? first turns all spaces to question marks (hoping that they cannot be present in file names), and ?s converts back. In between we can safely call the original notdir function.

For an excellent summary on GNU Make and spaces in file names, see GNU Make meets file names with spaces in them.

like image 155
Ville Laurikari Avatar answered Oct 16 '22 07:10

Ville Laurikari