5

我在 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两个路径并返回两者的“文件部分” (即,spacefoo)。奇怪的是,它TARGET被正确地转义了。不知何故,在 rule 或 inside $(notdir),反斜杠转义被忽略了。

我在这里做错了什么?

4

3 回答 3

9

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

这应该有效:

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

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

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

有关 GNU Make 和文件名中的空格的精彩总结,请参阅GNU Make 与文件名中的空格相遇

于 2009-07-27T18:45:28.407 回答
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.

于 2013-05-25T00:02:25.830 回答
-1

这只是在黑暗中拍摄:

TOP='"/home/chris/src/tests/make/space test"'
于 2009-07-27T18:32:15.937 回答