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

时间:2009-07-27 18:22:24

标签: 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)

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

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

但是,如果我在包含空格的目录中使用它,比如说space test,那么$(notdir)会做错事:

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

这里发生的事情是$(notdir)/tmp/space test/foo解释为两个路径并返回 both 的“文件部分”(即{{1} 1}}和space)。奇怪的是,foo被正确转义;不知何故,在规则内或TARGET内,反斜杠转义被忽略。

我在这里做错了什么?

3 个答案:

答案 0 :(得分:9)

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

这应该有效:

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

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

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

有关文件名中GNU Make和空格的精彩摘要,请参阅GNU Make meets file names with spaces in them

答案 1 :(得分:0)

这只是黑暗中的一击:

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

答案 2 :(得分:0)

假设你有一个Unix shell,你可以炮轰:

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

类似的策略可以适用于其他功能。只需记住变量周围的引号,该变量包含要作为单个参数处理的受空白感染的文本。这也可以保护您免受其他特殊字符的影响(引号除外!)。这是一个双反斜杠转义通配符glob结果中任何空格的示例:

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

Windows现在也将括号放在目录名中:C:\Program Files (x86)\我还不清楚使用make时这会产生什么影响。