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

老子叫甜甜 提交于 2019-12-05 00:39:27

问题


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?


回答1:


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.




回答2:


Assuming you have a Unix shell, you could shell out:

notdirx = $(shell basename '$1')
dirx = $(shell dirname '$1')

A similar strategy could apply to other functions. Just remember the quote marks around the variable that contains the whitespace-infected text that you want to treat as a single argument. This will also protect you from other special characters (except for quote marks!). Here's an example to double-backslash escape any spaces in the result of a wildcard glob:

$(shell ls -1 '*.foo' | sed 's/ /\\\\ /g')

Windows is putting parentheses in directory names now, too: C:\Program Files (x86)\ It's not yet clear to me what are the implications of this when using make.




回答3:


This is just a shot in the dark:

TOP='"/home/chris/src/tests/make/space test"'


来源:https://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!