From dc8ae67f7272ec9dcf0712f71520f1ea98707691 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 28 Apr 2016 16:20:27 -0400 Subject: [PATCH] Update the makefile with my new sedative approach to finding a fixed point. --- makefile | 86 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/makefile b/makefile index 6cd7eee..db6de3f 100644 --- a/makefile +++ b/makefile @@ -27,42 +27,76 @@ SRCS = $(PN).tex $(shell kpsewhich $(BIBS)) $(shell kpsewhich $(MJOTEX)) # The first target is the default, so put the PDF document first. # -# The voodoo here is to avoid rebuilding the project when nothing has -# changed. Each compilation pass with pdflatex will produce a new aux -# file, even if nothing has changed. That cases Make to think that we -# need to regenerate the bbl file, which in turn means we need to -# rebuild the whole project... +# This voodoo is all designed to find a "fixed point" of calling +# $(LATEX). When you build a LaTeX document, it requires an unknown +# number of compilation passes. How do you know when to stop? Easy, +# stop when the output file stops changing! But how to encode that +# in a makefile? # -# To avoid that, we save a copy of the current aux file and compare it -# to the new one afterwards. If the files are the same, great, put the -# old one (with the old timestamp) back. If not, we need to compile -# again, so we just invoke $(MAKE) again on this target. +# At the start of this target, we call $(LATEX) to compile $(PN).tex. +# If you ignore the "sed" for now, then the next step is to check for +# the existence of a "previous" file. If there isn't one, this is the +# first time that we've tried to build the PDF. In that case, take the +# PDF that we've just built and make *that* the previous file. Then +# start all over. If there is a previous file, then this is the second +# (or more) time that we've tried to build the PDF. We diff the PDF +# file that we've just built against the previous file; if they're the +# same, then we've succeeded and stop. Otherwise, we make the new PDF +# the previous file, and start all over. The end result is that we +# will loop until the newly-created PDF and the previous file are +# identical. # -# The process is kind of like finding a fixpoint of `make` with -# respect to the contents of the aux file. +# But what about the "sed" call? By default, pdflatex will compile the +# creation date, modification date, and a unique ID into the output +# PDF. That means that two otherwise-identical documents, created +# seconds apart, will look different. We only need to know when the +# *contents* of the document are the same -- we don't care about the +# metadata -- so sed is used to remove those three nondeterministic +# pieces of information. # -# Why use the aux file and not the PDF, which is what we really care -# about? The pdflatex tool currently embeds the creation/modification -# time into the PDF, so every new version will differ from the last, -# making comparisons meaningless. This is fixed in pdftex v1.40.17 -# thanks to Debian's SOURCE_DATE_EPOCH initiative. When that version -# of pdflatex makes it into TeX Live 2016, we can replace this junk -# with something smarter +# The creation and modification dates should become optional in pdftex +# v1.40.17 thanks to Debian's SOURCE_DATE_EPOCH initiative. When that +# version of pdflatex makes it into TeX Live 2016, we can replace +# those two sed scripts with something smarter. # -$(PN).pdf: $(SRCS) $(PN).aux $(PN).bbl - mv $(PN).aux $(PN).aux.bak - $(LATEX) $< && $(LATEX) $< - if cmp -s $(PN).aux $(PN).aux.bak; then \ - mv $(PN).aux.bak $(PN).aux; \ +$(PN).pdf: $(SRCS) $(PN).bbl + $(LATEX) $(PN).tex + + sed --in-place \ + -e '/^\/ID \[<.*>\]/d' \ + -e "s/^\/\(ModDate\) (.*)/\/\1 (D:19700101000000Z00'00')/" \ + -e "s/^\/\(CreationDate\) (.*)/\/\\1 (D:19700101000000Z00'00')/" \ + $@ + + if [ ! -f $@.previous ]; then \ + mv $@ $@.previous; \ + $(MAKE) $@; \ + fi; + + if cmp -s $@ $@.previous; then \ + rm $@.previous; \ else \ + mv $@ $@.previous; \ $(MAKE) $@; \ fi; + $(PN).aux: $(SRCS) - $(LATEX) $< + $(LATEX) $(PN).tex + -$(PN).bbl: $(PN).aux - bibtex $< +# The pipe below indicates an "order-only dependency" on the aux file. +# Without it, every compilation of $(PN).tex would produce a new +# $(PN).aux, and thus $(PN).bbl would be rebuild. This in turn causes +# $(PN).pdf to appear out-of-date, which leads to a recompilation of +# $(PN).tex... and so on. The order-only dependency means we won't +# rebuild $(PN).bbl if $(PN).aux changes. +# +# As a side effect, we now need to depend on $(SRCS) here, since we +# won't pick it up transitively from $(PN).aux. +# +$(PN).bbl: $(SRCS) | $(PN).aux + bibtex $(PN).aux # Clean up leftover junk. -- 2.44.2