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:
- The project Makefile must writes output to a sub-directory of the directory it is in.
- To make clean you go up one directory and delete the entire hierarchy.
- Then to make you create a new directory, check out the sources, enter the directory and run make.