Make Clean: Usman's Law

[article]
Summary:

Usman's Law (named after a smart coworker of mine who spent months working with customer Makefiles). make clean is intended to take you back to a state where everything will be rebuilt from scratch.   Often times it doesn't. Here's why.

Usman's Law (named after a smart coworker of mine who spent months working with customer Makefiles). make clean is intended to take you back to a state where everything will be rebuilt from scratch.   Often times it doesn't. Here's why.

The Human Factor

Here's the clean rule from the OpenSSL Makefile:

clean:

~    rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff $(EXE)


Notice how it's a long list of, clearly human maintained, things that need to be deleted to get back to a clean state.  Human maintained means human error.  Suppose someone adds a rule that creates a temporary file with a fixed name.  That temporary file needs adding to the clean rule; mostly likely it won't be.

Usman's Law strikes.
<size=12pt>

Poor Naming

Here's a snippet found in many automatically generated Makefiles:

mostlyclean::

~    rm -f *.o

clean:: mostlyclean

~    -$(LIBTOOL) --mode=clean rm -f $(program) $(programs)

~    rm -f $(library).a squeeze *.bad *.dvi *.lj

extraclean::

~    rm -f *.aux *.bak *.bbl *.blg *.dvi *.log *.pl *.tfm *.vf *.vpl

~    rm -f *.*pk *.*gf *.mpx *.i *.s *~ *.orig  *.rej *\#*

~    rm -f CONTENTS.tex a.out core mfput.* texput.* mpout.*


Here there are three sorts of clean which appear to have different degrees of cleanliness: mostlyclean, clean and extraclean.

mostlyclean just deletes the object files compiled from source.

~ clean does that plus the generated library and a few other

files.   You'd think that extraclean would delete more than the

other two, but it actually deletes a different set of files.

You can't tell from the naming what does what.  And I've seen others with reallyclean, veryclean, deepclean and even partiallyclean!

Usman's Law strikes.

<size=12pt>Silent Failure

Here's another Makefile snippet that works some of the time:

clean:

~    @-rm *.o &> /dev/null


The @ means that the command isn't echoed.  The - means that any error return is ignored and all output is redirected,

with &>, to /dev/null making it invisible.   Since

there's no -f on the rm command a failure (say a permissions problem) will be totally unnoticed.

Usman's Law strikes.
<size=12pt>
Recursive Clean

Most Makefiles are recursive and make clean has to be recursive too, so you see the pattern:

SUBDIRS := foo bar baz

CLEAN_SUBDIRS := $(addprefix clean_,$(SUBDIRS))

clean: $(CLEAN_SUBDIRS)

$(CLEAN_SUBDIRS):

    @make -C $(subst clean_,,$@) clean


The problem with this is that it means that make clean has to be maintained throughout the code hierarchy leading to more opportunity for error.

Usman's Law strikes.

<size=12pt>The only way to win is not to play

Because of the pitfalls of make clean the best way is not to

have a make clean.   The most reliable method is as follows:

    1. The project Makefile must writes output to a sub-directory of the directory it is in.
    2. To make clean you go up one directory and delete the entire hierarchy.

 

  1. Then to make you create a new directory, check out the sources, enter the directory and run make.

About the author

CMCrossroads is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.