vog vog - 1 month ago 6
Bash Question

Elegant way to remove target file if a Make rule fails

I have a rule in my Makefile that roughly looks like this:

target_file: src_file
some_tool src_file > target_file


(Of course, in reality I'm using
$@
and
$<
, but for this question I prefer a more explicit style.)

The problem is that
target_file
is always created by the shell with a fresh timestamp, even if
some_tool
fails. In that case, an empty
target_file
exists, and even if I fix the underlying issue, it won't be rebuilt until I manually remove
target_file
or touch
src_file
.

Also,
some_tool
only writes to standard output, so I can't work around this through a cleaner approach such as
some_tool ... -o target_file
.

My current approach is to remove

target_file: src_file
some_tool src_file > target_file || rm -f target_file


However, this has the disadvantage that
Make
won't notice if
some_tool
fails, because in that case
rm
takes over and returns exitcode 0 (succeess).

Another approach may be:

target_file: src_file
some_tool src_file > target_file.tmp
mv target_file.tmp target_file


But that kind of code is tedious and on failure leaves an annoying file
target_file.tmp
behind.

Is there a more elegant way to solve this problem?

Answer

You could use the special target .DELETE_ON_ERROR:

If .DELETE_ON_ERROR is mentioned as a target anywhere in the makefile, then make will delete the target of a rule if it has changed and its recipe exits with a nonzero exit status, just as it does when it receives a signal.

All it takes is one line:

.DELETE_ON_ERROR:

And all rules that fail will have their target removed.

Comments