考虑以下用户定义的函数:
define func =
if [ -f $(1) ]; then \
printf "'%s' is a file\n" '$(1)'; \
printf "This is a relatively long command that"; \
printf " won't fit on one line\n"; \
fi
endef
all:
$(call func,foo)
这将输出以下内容:
$ make
if [ -f foo ]; then printf "'%s' is a file\n" 'foo'; printf "This is a rel
atively long command that"; printf " won't fit on one line\n"; fi
为了便于阅读,我希望make
在多行上打印命令,
如Makefile中所写。我该如何做到这一点?
以下按我想要的方式工作,但不允许参数化 功能:
filename := foo
.PHONY: foo
foo:
if [ -f $(filename) ]; then \
printf "'%s' is a file\n" '$(filename)'; \
printf "This is a relatively long command that"; \
printf " won't fit on one line\n"; \
fi
输出:
$ make foo
if [ -f foo ]; then \
printf "'%s' is a file\n" 'foo'; \
printf "This is a relatively long command that"; \
printf " won't fit on one line\n"; \
fi
我明显的第一直觉是逃避反斜杠:
define func =
if [ -f $(1) ]; then \\
printf "'%s' is a file\n" '$(1)'; \\
printf "This is a relatively long command that"; \\
printf " won't fit on one line\n"; \\
fi
endef
输出:
$ make
if [ -f foo ]; then \\
printf "'%s' is a file\n" 'foo'; \\
printf "This is a relatively long command that"; \\
printf " won't fit on one line\n"; \\
fi
/bin/sh: \: command not found
'foo' is a file
/bin/sh: line 1: \: command not found
This is a relatively long command that/bin/sh: line 2: \: command not found
won't fit on one line
/bin/sh: line 3: \: command not found
make: *** [Makefile:11: all] Error 127
好的,为什么不试试\\\
?
$ make
if [ -f foo ]; then \ printf "'%s' is a file\n" 'foo'; \ printf "This is a
relatively long command that"; \ printf " won't fit on one line\n"; \ fi
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [Makefile:11: all] Error 1
有趣。我们去四点......
$ make
if [ -f foo ]; then \\\\
printf "'%s' is a file\n" 'foo'; \\\\
printf "This is a relatively long command that"; \\\\
printf " won't fit on one line\n"; \\\\
fi
/bin/sh: \\: command not found
'foo' is a file
/bin/sh: line 1: \\: command not found
This is a relatively long command that/bin/sh: line 2: \\: command not found
won't fit on one line
/bin/sh: line 3: \\: command not found
make: *** [Makefile:11: all] Error 127
现在我们又回到了上次的位置。
这是唯一可行的方法:
define func =
if [ -f $(1) ]; then #\\
printf "'%s' is a file\n" '$(1)'; #\\
printf "This is a relatively long command that"; #\\
printf " won't fit on one line\n"; #\\
fi
endef
输出:
$ make
if [ -f foo ]; then #\\
printf "'%s' is a file\n" 'foo'; #\\
printf "This is a relatively long command that"; #\\
printf " won't fit on one line\n"; #\\
fi
但男人,看起来很丑陋,而且感觉很乱。必须有一个更好的 这样做的方式。或者我只是在第一个错误的方式 放置?
在我看来,make
只是被当时发生的魔法所困惑
逃避食谱中的换行符。打印到终端的线条
执行与shell看到的不匹配。这应该被视为一个错误吗?
我在Cygwin上使用GNU Make 4.2.1。
澄清一下:make
通常会对配方中的尾部反斜杠进行特殊处理。它们并不像其他地方那样表明线路延续。相反,它们表明多个配方行将被视为单个命令,并且它们将完整地传递给shell。
如果不在配方中,但定义变量,则此特殊处理不适用。简单地连接线,如例1所示。这是预期的。
我希望将双反斜杠转换为变量中的单个字面反斜杠,但是会保留两个反斜杠。当变量在配方中展开时,我希望make
的行为就像配方在每一行的末尾都有\\
一样。如果是这种情况,则每行将单独执行。但正如您在示例3和示例6中看到的那样,这些行一起执行。
关键是,可以从变量的扩展中获得魔法反斜杠解析。问题是这种行为的机制是不一致和令人困惑的。
答案 0 :(得分:2)
的Urk!这是由于 make 的noddy解析器。
食谱按原样存储。 当 make 即将调用shell时,它们会被扩展。 整个配方一旦扩展, 第一行传递给shell。 如果该命令成功,则运行第二个命令。 洗涤,冲洗,重复。 保留了行尾的反斜杠, 结果是下一行与第一行同时传递。
然而,在递归变量定义中, 在读取定义
时,删除行末尾的反斜杠define oneline =
aa \
bb \
cc
endef
$(error [$(value oneline)])
给出了
$ make
Makefile:9: *** [ aa bb cc]. Stop.
我们需要按下 make 的语法,以便变量扩展为完全此文本:
target:
if [ -f foo ]; then \
printf "'%s' is a file\n" 'foo'; \
printf "This is a relatively long command that"; \
printf " won't fit on one line\n"; \
fi
然后我们只需通过类似
的内容输入 make$(eval ${var})
只需用空格替换每个换行符 - 反斜杠 - 换行符 - 标签使用$(subst)
进行四元组。
执行此操作的功能:
empty :=
tab := ${empty} # Trailing tab
define \n :=
endef
stanza = $(subst ${\n}, \${\n}${tab})
检查它是否有效:
define func =
if [ -f $1 ]; then
printf "'%s' is a file\n" '$1';
printf "This is a relatively long command that";
printf " won't fit on one line\n";
fi
endef
$(error [$(call stanza,$(call func,foo))])
,并提供:
Makefile:23: *** [ if [ -f foo ]; then \
printf "'%s' is a file\n" 'foo'; \
printf "This is a relatively long command that"; \
printf " won't fit on one line\n"; \
fi]. Stop.
请注意,func
的定义现在在其行的末尾没有注释。
define \n :=
endef
empty :=
tab := ${empty} # Trailing tab
stanza = $(subst ${\n}, \${\n}${tab},$1)
define func =
if [ -f $1 ]; then
printf "'%s' is a file\n" '$1';
printf "This is a relatively long command that";
printf " won't fit on one line\n";
fi
endef
define rule =
target:
echo vvv
$(call stanza,$(call func,foo))
echo ^^^
endef
$(eval ${rule})
导致
$ touch foo; make -R --warn
echo vvv
vvv
if [ -f foo ]; then \
printf "'%s' is a file\n" 'foo'; \
printf "This is a relatively long command that"; \
printf " won't fit on one line\n"; \
fi
'foo' is a file
This is a relatively long command that won't fit on one line
echo ^^^
^^^
一项有趣的学术活动。 仍然不能把文字反斜杠放在:)
答案 1 :(得分:1)
define newline :=
$(strip)
$(strip)
endef
define func =
if [ -f $(1) ]; then \$(newline)\
printf "'%s' is a file\n" '$(1)'; \$(newline)\
printf "This is a relatively long command that"; \$(newline)\
printf " won't fit on one line\n"; \$(newline)\
fi
endef
func2 = if [ -f $(1) ]; then \$(newline) printf "'%s' is a file\n" '$(1)'; \$(newline) printf "This is a relatively long command that"; \$(newline) printf " won't fit on one line\n"; \$(newline)fi
all:
$(call func,foo)
@echo --------------
$(call func2,foo)
第一个似乎是空间剥离的。第二个看起来很不错,但是......好吧,好像被卡在岩石和硬地之间:/
答案 2 :(得分:0)
我找到了一个似乎更好的解决方案(尽管仍然很笨拙):
define func =
if [ -f $(1) ]; then $\\
printf "'%s' is a file\n" '$(1)'; $\\
printf "This is a relatively long command that"; $\\
printf " won't fit on one line\n"; $\\
fi
endef
all:
@echo vvvvvvvv
$(call func,foo)
@echo ^^^^^^^^
输出:
$ make
vvvvvvvv
if [ -f foo ]; then \
printf "'%s' is a file\n" 'foo'; \
printf "This is a relatively long command that"; \
printf " won't fit on one line\n"; \
fi
'foo' is a file
This is a relatively long command that won't fit on one line
^^^^^^^^
我认为这是这样的:
在第一次扫描连续行时,$
被忽略,因此
解析器看到\\
,假定反斜杠已转义,并保留行
完好无损。
扩展功能时,$\
被识别为变量。假设
您尚未实际分配名为\
的变量,则该变量扩展为
什么都没有。
现在,我们在行尾只剩下一个反斜杠,即 就像是按字面意思输入配方一样。