如何在文件名包含空格的情况下可靠地使用GNUMake?

7
我想使用GNUMake来运行一个基于规则的makefile,该文件在目录结构中构建一组C文件(在Windows文件系统上)。
根目录、某些子目录和某些文件名包含空格。
例如文件:"C:\Documents and Settings\<username>\My Documents\Test Dir\Build Me.c" 当文件路径包含空格时,GNUMake无法正常工作。我已经阅读了解决此问题的可能方法(从我的文件名中删除空格,使用8.3格式,用?\\替换空格等),但它们都不完美(或者说它们是吗?)
是否有一个万能方法可以解决这个问题?
顺便说一句,我被困在GNUMake中,无法使用其他make工具。
6个回答

3
最简单的方法是确保文件名正确。
如果无法做到这一点,可以编写命令以在文件名周围放置双引号。最简单和最安全的方法是将所有文件名放入宏中;其中的技巧是必须转义双引号,否则Make会想要吞掉它自己。
因此: FN="\"C:\My Documents\myfiles.c\"" FN2="C:\My Documents\myfile2.c"
或者使用 $(CC) $(CFLAGS) "$(FN2)"
这里的技巧是使用echo回显您的命令行。
echo $(CC) $(CFLAGS) "$(FN2)"

或者使用make -d命令获取所有make尝试执行的详细信息。

您可能需要对此进行一些调整,特别是您可能需要重复进行转义。


11
“修复文件名”?这些文件名没有损坏。无法处理空格的工具是有问题的。示例路径是微软的标准,甚至可能是一种推动开发人员修复无法处理空格的有问题工具的策略。 - Qwertie
1
不,是使用与UNIX标准不匹配的文件名的工具出了问题。还有操作系统。 - Charlie Martin
允许空格的操作系统和工具是有问题的?! - Qwertie
2
对。你们这些孩子离开我的草坪。 - Charlie Martin

2
我在http://www.mail-archive.com/help-make@gnu.org/msg05201.html上找到了很好的灵感,这激发了我。我的测试应用程序由一个目录组成,其中包含从YouTube下载的二战时期的爵士FLV文件和一个音频子目录,我想将每个FLV文件的OGA音频版本存储到其中。当然,文件名包含空格。然后,我想运行ffmpeg2theora。
这是我自己编写的GNUMake Makefile。感谢本站和上面提到的参考网站上的所有提示!
sq = $(subst $(sp),?,$1)
qs = $(subst ?,$(sp),$1)

e :=
sp := $(e) $(e)

FLVS := $(foreach file,var,$(call sq,$(wildcard *.flv)))
FLVS := $(subst .flv?,.flv ,$(FLVS))

AUDIOS := $(patsubst %.flv,audio/%.oga,$(FLVS))

.PHONY: audios show

audios: $(AUDIOS)

$(AUDIOS) : $(FLVS)
    ffmpeg2theora --novideo -o "$(call qs,$@)" "$(call qs,$(notdir $(patsubst %.oga,audio/%.flv,$@)))"

show:
    echo $(FLVS)
    echo $(AUDIOS)

或者您可以替换其他字符,并在需要时将它们转换回空格。s+ = $(subst \ ,+,$1)+s = $(subst +,\ ,$1)$(call s+,foo bar): $(call s+,bar baz)`@echo 从 $(call +s,$<) 制作 $(call +s,$@)` - Mr_Moneybags

2

您可以在makefile中转义空格,例如:

$(CC) $(CFLAGS) 'C:\Documents\ and\ Settings\<username>\My\ Documents\Test\ Dir\Build Me.c'

我已经添加了单引号以防万一,但我不知道如果你使用的是Windows终端(而不是Cygwin等),这是否有效。


可能可以,但我手头没有Windows安装程序来测试以确保。虽然我想不出为什么这不会起作用的原因。 - Dana the Sane

1

我通常使用的是 Dana the Sane 和 Brian Yoder 的答案的结合。

你只需要使用 $(subst) 函数将所有空格替换为转义空格即可。例如:

empty := 
space := $(empty) $(empty)
program_files := $(subst $(space),\$(space),$(ProgramFiles))

(请注意,在某些旧版本的Windows上,您还需要使用另一个$(subst)将路径反斜杠更改为斜杠)

0

如果路径名中的空格只在“根”部分中,您可以将该目录挂载到没有空格的路径上。有多种方法可以做到这一点:从命令行(“net use”或“subst”)或从资源管理器(工具>映射网络驱动器)。因此,C:\Documents and Settings\\My Documents\Test Dir" 可能会变成 X:\BuildMe.c

但是,如果文件名中或“根”构建目录下的目录中有空格,则可能没有完美的解决方案。我已经使用了您提到的其他建议(8.3名称,用不同字符替换空格),它们可以工作,但它们也有自己的问题。


它需要在所有情况下都能工作。即使根目录包含空格,子目录本身以及文件名本身也是如此。 - demoncodemonkey

0

我只需在有问题的字符串周围添加单引号:'$(TARGET_DIR)'

例如:(这帮助我在Windows上正确地使用erlang.mk!)

app:: $(C_SRC_ENV)
    @mkdir -p priv/
    $(c_src_verbose) $(CC) $(CFLAGS) $(C_SRC_DIR)/*.c -fPIC -shared -o $(C_SRC_OUTPUT) \
        -I '$(ERTS_INCLUDE_DIR)' $(C_SRC_OPTS)

'$(ERTS_INCLUDE_DIR)' 现在正确地扩展为 'c:/Program Files/erl7.0/erts-7.0/include/'

使用 make -d 也有助于揭示无效路径


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接