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?
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.