在带有空格的路径上使用 Make $(dir) 或 $(notdir)
题
我在 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。, 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,$@)'
这定义了“空间安全”版本 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"'
不隶属于 StackOverflow