我在 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 作为 路径并返回“文件部分” 两个都 (IE。, spacefoo)。奇怪的是 TARGET 正确逃脱;不知何故,在规则内或内部 $(notdir), ,反斜杠转义被忽略。

我在这里做错了什么?

有帮助吗?

解决方案

$(notdir) GNU Make 中的函数接受一个参数列表,参数之间用空格分隔。某些函数支持转义空格 \\, , 但 $(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 满足文件名中含有空格的情况.

其他提示

假设你有一个Unix外壳,可以掏出:

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

一个类似的策略可以应用于其他功能。只要记住周围包含您要视为一个参数的空白感染文字变量引号。这也将保护您免受其他特殊字符(除引号!)。下面就以双反斜线的示例逸出任何空格在一个通配符水珠的结果:

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

Windows正在投入目录名称后括号现在,太:C:\Program Files (x86)\它目前还不清楚我是什么这一点使用时make的影响

这是刚刚在黑暗中拍摄:

TOP='"/home/chris/src/tests/make/space test"'
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top