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

Ben*_*kla 13 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
Run Code Online (Sandbox Code Playgroud)

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

$ 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
Run Code Online (Sandbox Code Playgroud)

Eri*_*ski 20

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

all: foo.o

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

.DELETE_ON_ERROR:
Run Code Online (Sandbox Code Playgroud)

以下是此makefile的示例:

$ gmake
echo bogus! > foo.o
exit 1
gmake: *** [foo.o] Error 1
gmake: *** Deleting file `foo.o'
Run Code Online (Sandbox Code Playgroud)

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


rei*_*ost -1

是的,这绝对是需要牢记的事情。

但有时您可以接受命令失败,但不想重试,因为错误只会重复出现。

在这种情况下,留下空结果就可以了。只是不要让后续处理依赖于该文件中存在有意义的内容。