是常见的Makefile成语“> $ @”(将输出重定向到目标)错误?

时间:2010-08-27 18:44:08

标签: makefile

很难相信,但在我看来,常见的Makefile成语“> $ @”是错误的。特别是,其规则具有失败但使用此重定向的命令的目标将在第一次失败但不是后续失败。这是因为即使命令失败,重定向也会在创建最新(尽管是零长度)目标的意义上“成功”。

在我看来,正确的做法是重定向到临时并成功将此临时重命名为目标。

这是和Makefile的例子:

bad-target:
        command-that-will-fail > $@

good-target:
        command-that-will-fail > $@.tmp || ( rm $@.tmp; false )
        mv $@.tmp $@

clean:
        rm -f bad-target good-target

这是一系列说明问题及其解决方案的命令:

$ make clean
rm -f bad-target good-target

$ make bad-target
command-that-will-fail > bad-target  
/bin/sh: command-that-will-fail: not found  
make: *** [bad-target] Error 127

$ make bad-target
make: `bad-target' is up to date.

$ make good-target
command-that-will-fail > good-target.tmp || ( rm good-target.tmp; false )  
/bin/sh: command-that-will-fail: not found  
make: *** [good-target] Error 1

$ make good-target
command-that-will-fail > good-target.tmp || ( rm good-target.tmp; false )  
/bin/sh: command-that-will-fail: not found  
make: *** [good-target] Error 1

3 个答案:

答案 0 :(得分:19)

如果您正在使用GNU make,您还可以将.DELETE_ON_ERROR特殊目标添加到您的makefile中。如果在执行该文件的命令期间出现错误,这将导致make删除输出文件:

all: foo.o

foo.o:
        echo bogus! > $@
        exit 1

.DELETE_ON_ERROR:

以下是此makefile的示例:

$ gmake
echo bogus! > foo.o
exit 1
gmake: *** [foo.o] Error 1
gmake: *** Deleting file `foo.o'

这比您的版本更容易使用,因为您无需修改​​makefile中的每个规则。

答案 1 :(得分:1)

也许这是一个明显的解决方案,但许多常见命令提供-o标志或类似标记。因此,您应该使用以下规则来代替输出重定向:

target: target.dep
    some_command target.dep -o $@

如果命令失败,则不会创建输出文件。我没有多次在makefile中使用输出重定向。

答案 2 :(得分:0)

是的,这绝对值得记住。

但是有时候你可以在命令失败的情况下使用它并且你不想重试它,因为错误只会重演。

在这种情况下,留空结果是可以的。只是不要对该文件中有意义的内容进行后续处理。