Daniel Standage
Daniel Standage

Reputation: 8314

Make: .DELETE_ON_ERROR for directory targets

GNU Make includes a special target called .DELETE_ON_ERROR. If this is included in your Makefile, Make will delete any target whose build sequence completes with a non-zero return status. This is helpful so that in subsequent invocations Make does not assume that the target has been properly built.

Here's a dummy example.

.DELETE_ON_ERROR:

out.dat:    in.dat
            touch out.dat
            false

Because false gives a non-zero return value, the build is considered failed and Make deletes the out.dat target. This is the advertised and expected behavior. However, this behavior does not seem to be preserved when the target is a directory. Consider another dummy example.

.DELETE_ON_ERROR:

outdir/:    in.dat
            mkdir outdir/
            false

In this case, the build fails again but Make does not remove the outdir directory. Is there any way I can instruct Make to do this?

Upvotes: 10

Views: 4576

Answers (1)

dash-o
dash-o

Reputation: 14493

As noted in the comments, it is hard to use timestamps on directory. Few options:

  • proxy target (%.dir)
  • Atomic update using temporary folder.

Using proxy target, Makefile can be modified to incude a '%.done' target, which will embed the cleanup logic.

.PHONY: %.dir

outdir.dir:
    $(MAKE) outdir ; if [ $? -ne 0 ] ; then echo CLEANUP $@ ; rm -rf dir ; false ; fi

outdir: ...  # as before

And use the outdir.dir as a dependency. Not elegant, but will get the work done. May be possible to to convert into a rule (disclaimer: I did not test this approach).

.PHONY %.dir

%.dir:
    $(MAKE) $* ; if [ $? -ne 0 ] ; then echo CLEANUP $* ; rmd -rf $* ; false ; fi

Another variation is to change the outdir to add a "done" indicator file (if completed successfully), and use the proxy target to validate

%.dir:
    $(MAKE) $* ; if [ ! -f $*.done ] ; then rm -rf $* ; false ; fi

outdir:
   ... commands, any can fail.
   touch $*.done

As last resort (or first option, depending on your situation), consider, 'atomic' build for outdir - creating a temporary folder, and renaming it to outdir on success

outdir:
    rm -rf [email protected] $@
    mkdir [email protected]
    # Command to create outdir.new here
    mv [email protected] $@

Upvotes: 1

Related Questions