代码之家  ›  专栏  ›  技术社区  ›  Charles Duffy

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

  •  5
  • Charles Duffy  · 技术社区  · 15 年前

    我在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'
    

    这里发生的是 $(Nodir) 解释 /tmp/space test/foo 作为 路径并返回的“文件部分” 二者都 (即, space foo )奇怪的是 TARGET 被正确地逃脱;不知何故,在规则内部或内部 $(Nodir) ,反斜杠转义将被忽略。

    我在这里做错什么了?

    3 回复  |  直到 10 年前
        1
  •  9
  •   binOr    13 年前

    这个 $(notdir) gnu make中的函数接受由空格分隔的参数列表。有些函数支持使用 \\ 但是 $(Nodir) 不是他们中的一个。

    这应该有效:

    s? = $(subst $(empty) ,?,$1)
    ?s = $(subst ?, ,$1)
    notdirx = $(call ?s,$(notdir $(call s?,$1)))
    
    $(TARGET):
        touch '$(call notdirx,$@)'
    

    这定义了“空间安全”版本的 notdir 打电话 notdirx . 很简单: s? 首先将所有空格转换为问号(希望它们不能出现在文件名中),然后 ?s 转换回来。在两者之间,我们可以安全地称之为原始 诺迪尔 功能。

    有关gnu make和文件名中的空格的优秀摘要,请参见 GNU Make meets file names with spaces in them .

        2
  •  0
  •   Oktalist    11 年前

    假设您有一个unix shell,您可以shell出:

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

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

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

    Windows现在也在目录名中加括号: C:\Program Files (x86)\ 我还不清楚在使用时这意味着什么 make .

        3
  •  0
  •   user229044    10 年前

    这只是黑暗中的一个镜头:

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