我发现GNU Make 4.1和3.81之间的行为有所不同,想知道我的代码是否不符合POSIX规范,而后者更严格地执行了4,或者是否还有其他问题。
我将失败案例提炼到该Makefile
.POSIX:
all: test-b
test-a:
cat a.txt b.txt c.txt >results.txt
test-b:
cat {a,b,c}.txt >results.txt
假设这些文件是使用cat {a,b,c}.txt
创建的,则目标test-a
始终有效,而test-b
可以在Make 3.81上运行,但在4.1上失败。
3.81的输出:
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i386-apple-darwin11.3.0
$ make
cat {a,b,c}.txt >results.txt
$ echo $?
0
4.1的输出:
$ make --version
GNU Make 4.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ make
cat {a,b,c}.txt >results.txt
cat: {a,b,c}.txt: No such file or directory
Makefile:9: recipe for target 'test-b' failed
make: *** [test-b] Error 1
$ echo $?
2
cat
命令实际上在3.81中失败了,只是没有指出它,因为GNU的更高版本提到了在调用目标命令时将-e
标志传递给shell。使它更符合POSIX,但我看不到该命令可能失败的原因。
我假定通配符仅由外壳程序处理,所以我看不到通过make target命令调用外壳程序应该有什么不同。
这些行为正确吗?如果类似的通配符在Makefile中不起作用,我可以假定其他哪些通配符起作用?
即使从文件中删除了test-b
, .POSIX:
在4.1中仍然失败。
答案 0 :(得分:2)
食谱被发送到外壳。它们不是由make解释的。因此,您的问题是,shell是否支持花括号扩展?
这取决于使用哪个shell。 POSIX标准sh不支持它们。它们由bash(和许多其他shell)支持。
Make始终调用/bin/sh
,无论您个人使用什么shell,除非您将make SHELL
变量专门设置为其他变量。在某些系统上,/bin/sh
是到/bin/bash
的符号链接,因此它们是同一对象(bash在以/bin/sh
调用时以“ POSIX仿真”模式运行,但大多数bash功能仍然可用) 。其他系统使用不同的shell,例如破折号/bin/sh
,它们没有额外的bash功能。
因此,您可以(a)没有可移植的makefile并假设/bin/sh
与/bin/bash
相同,(b)在makefile中设置SHELL := /bin/bash
强制其使用始终使用bash(但在未安装bash的系统上失败),或(c)编写makefile配方以仅使用POSIX sh功能,因此无论/bin/sh
使用哪个shell,它都可以工作。