2008-09-24
How we lie to our Makefiles
I spent part of today updating the system that generates data files for
our mail system to add a new computed data file. This system is built
around a Makefile
, and so I added a new rule, which looks like this:
$(CL): $(DL) $(AUXFILE) crunch-dl $(DL) $(AUXFILE) >$(CL).new mv -f $(CL).new $(CL)
(The rule is done in two stages so that we don't update the $(CL)
file
if the crunch-dl
script fails. If we just wrote directly to $(CL)
,
we could be left with an incomplete or empty $(CL)
that make
thinks
is up to date because it has a current timestamp.)
Those dependencies are a lie. Well, a lie by omission. The generated
file doesn't just depend on the data files, it also depends on the
crunch-dl
script that processes the data files; change the script and
you may well change the generated output. (You may not, but this is true
of changing any dependency.)
I commit this lie regularly, even routinely, although I am not sure why. Partly I think that it is a mindset; I think of Makefile rules in general as declaring the inputs that are turned into the output, and the script is not an 'input' as such so it gets left out. Partly I think that it is convention and habit, how I've always done things and seen them done, and thus that it would simply feel (and look) wrong to add the script as a dependency (especially because it isn't in the current directory).
(Of course, my conventions are mostly formed by reading and writing Makefiles for C programs, which have relatively little call for explicitly depending on the compiler. And once you start thinking about depending on the compiler, you also have to think about depending on important compiler flags, and most people don't want to go there.)