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/foo为2路和返回的"文件部分" 既(即,space和foo).这个奇怪的部分TARGET是正确逃脱的; 不知何故,在规则内部或内部$(notdir),反斜杠转义被忽略.
我在这做错了什么?
$(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文件名,其中包含空格.