Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 571
Daniel Standage Avatar asked Sep 09 '14 19:09

Daniel Standage


People also ask

What is $@ in makefile?

The file name of the target of the rule. If the target is an archive member, then ' $@ ' is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ' $@ ' is the name of whichever target caused the rule's recipe to be run.

What is .precious in makefile?

PRECIOUS to preserve intermediate files created by rules whose target patterns match that file's name. .INTERMEDIATE. The targets which . INTERMEDIATE depends on are treated as intermediate files. See Chains of Implicit Rules. .

What is a make target?

A 'make target' is basically a file that you want rebuilt. Make can't divine what you want built, so you have to tell it, implicitly or explicitly, what it should build.

What is the default make target?

By default, the goal is the first target in the makefile (not counting targets that start with a period). Therefore, makefiles are usually written so that the first target is for compiling the entire program or programs they describe.


1 Answers

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] $@
like image 180
dash-o Avatar answered Sep 19 '22 12:09

dash-o