在带空格的路径上使用Make $(dir)或$(notdir)

Chr*_*way 5 makefile path quoting

我在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)
Run Code Online (Sandbox Code Playgroud)

如果我在没有空格的目录中使用space-test它,比如说,它可以正常工作:

$ make
TOP='/tmp/space-test'
TARGET='/tmp/space-test/foo'
touch 'foo'
Run Code Online (Sandbox Code Playgroud)

但是,如果我在一个带空格的目录中使用它,比如说space test,那就$(notdir)错了:

TOP='/tmp/space\ test'
TARGET='/tmp/space\ test/foo'
touch 'space foo'
Run Code Online (Sandbox Code Playgroud)

这里发生的事情是$(notdir)解释/tmp/space test/foo2路和返回的"文件部分" (即,spacefoo).这个奇怪的部分TARGET是正确逃脱的; 不知何故,在规则内部或内部$(notdir),反斜杠转义被忽略.

我在这做错了什么?

Vil*_*ari 9

$(notdir)GNU Make中的函数采用由空格分隔的参数列表.有些函数支持转义空格\\,但$(notdir)不是其中之一.

这应该工作:

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

$(TARGET):
    touch '$(call notdirx,$@)'
Run Code Online (Sandbox Code Playgroud)

这定义了notdir被称为"空间安全"的版本notdirx.这很简单:s?首先将所有空格转换为问号(希望它们不能出现在文件名中),然后?s转换回来.在我们之间我们可以安全地调用原始notdir函数.

有关GNU Make和文件名中的空格的精彩摘要,请参阅GNU Make meet文件名,其中包含空格.