Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

makefile

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 > [email protected] || ( rm [email protected]; false )
        mv [email protected] $@

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
like image 868
Ben Denckla Avatar asked Aug 27 '10 18:08

Ben Denckla


People also ask

Which symbol should I use to redirect the standard output to a file?

Redirection is done using either the ">" (greater-than symbol), or using the "|" (pipe) operator which sends the standard output of one command to another command as standard input. As we saw before, the cat command concatenates files and puts them all together to the standard output.

Which character is used to redirect output in to an existing file in Linux?

Just as the output of a command can be redirected to a file, so can the input of a command be redirected from a file. As the greater-than character > is used for output redirection, the less-than character < is used to redirect the input of a command.

What does it mean to redirect to 2 >& 1?

So when you use 2>&1 you are basically saying “Redirect the stderr to the same place we are redirecting the stdout”. And that's why we can do something like this to redirect both stdout and stderr to the same place:"

What is meant by redirecting input output?

On a command line, redirection is the process of using the input/output of a file or command to use it as an input for another file. It is similar but different from pipes, as it allows reading/writing from files instead of only commands. Redirection can be done by using the operators > and >> .


1 Answers

If you're using GNU make, you may also add the .DELETE_ON_ERROR special target to your makefile. This will cause make to delete the output file if there is an error during execution of the commands for that file:

all: foo.o

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

.DELETE_ON_ERROR:

Here's an example of this makefile in action:

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

This is easier to use than your version, since you need not modify every rule in the makefile.

like image 103
Eric Melski Avatar answered Oct 20 '22 04:10

Eric Melski