is the common Makefile idiom "> $@" (redirecting output to the target) wrong?

Viewed 3794

It is hard to believe, but it seems to me that the common Makefile idiom "> $@" is wrong. In particular, a target whose rule has a command that fails but uses this redirection will fail the first time around but not subsequent times. This is because even though the command fails, the redirection "succeeds" in the sense of creating an up-to-date (albeit zero-length) target.

It seems to me that the correct thing to do is to redirect to a temporary and on success rename this temporary to the target.

Here's and example 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

And here's a sequence of commands illustrating the problem and its solution:

$ 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 Answers
Related