From fc10f284b59ac45c3c7617e442d71f7c976c110b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 14 Apr 2025 13:10:30 -0400 Subject: [PATCH] GNUmakefile: use a build directory The corresponding change to mjotex was made a while ago. --- GNUmakefile | 69 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 7d800b9..69c35e4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,13 +1,26 @@ # # Example makefile using mjotex and a BibTeX references database. # +# After defining $(PN) to be the name of your document, this will +# compile the source file $(PN).tex to $(PN).pdf. +# +# To support workflows where the document is kept open in a PDF reader +# during recompilation, the build process takes place in a separate +# $(BUILDDIR) directory that defaults to "build". Only when the build +# has completed do we move the resulting $(PN).pdf to the current +# directory. This avoids renaming or modifying the open document in +# place, which in turn helps prevent flickering, loss of bookmarks, et +# cetera, in several PDF readers. + +# The build directory. Not broken? Don't fix. +BUILDDIR=build # The latex compiler. The SOURCE_DATE_EPOCH=0 prevents the creation # and modification dates from being embedded as metadata into the # output file; that in turn is important because it allows us to tell # when the output stops changing (that is, when we are done). The # variable is supported in pdftex v1.40.17 and later. -LATEX = SOURCE_DATE_EPOCH=0 pdflatex -file-line-error -halt-on-error +LATEX = SOURCE_DATE_EPOCH=0 pdflatex -file-line-error -halt-on-error --output-directory $(BUILDDIR) # The name of this document. # @@ -59,30 +72,35 @@ SRCS += $(BEAMERMJOPATHS) # stop when the output file stops changing! But how to encode that # in a makefile? # -# At the start of this target, we call $(LATEX) to compile $(PN).tex. -# Afterwards, we check for the existence of a "previous" file. If -# there isn't one, then this is the first time that we've built the -# PDF. In that case, we take the PDF that we've just built and make it -# the "previous" file before starting all over. If, on the other hand, -# there already *was* a "previous" file, then this is the second (or -# third...) time that we've built the PDF. We diff the newly-built PDF -# against the "previous" file; if they're the same, then we've -# succeeded and stop. Otherwise, we make the new PDF the "previous" -# one, and start all over. The end result is that we will loop until -# the newly-created PDF and the "previous" one are identical. -# -$(PN).pdf: $(SRCS) $(PN).bbl +# At the start of this rule, we call $(LATEX) to compile $(PN).tex. +# It stores the resulting PDF in a separate "build" directory, so this +# will not actually create or overwrite the target $(PN).pdf. If there +# is no $(PN).pdf already, then we rename the new one to $(PN).pdf and +# we are done. But if there was a previous version, then we compare +# the two (new & old) versions. In either case, we rename the new one +# over the old one. But if the two differ, then we repeat this process +# in a loop until the just-built PDF is identical to the one from the +# previous iteration. +$(PN).pdf: $(SRCS) $(BUILDDIR)/$(PN).bbl $(LATEX) $(PN).tex - if [ -f $@.previous ] && cmp -s $@ $@.previous; then \ - rm $@.previous; \ - else \ - mv $@ $@.previous; \ - $(MAKE) $@; \ + if [ -f $@ ]; then \ + while ! cmp -s $@ $(BUILDDIR)/$(PN).pdf; do \ + mv $(BUILDDIR)/$(PN).pdf $@; \ + $(LATEX) $(PN).tex; \ + done; \ fi; + if grep -q 'Rerun to get' $(BUILDDIR)/$(PN).log; then \ + $(LATEX) $(PN).tex; \ + fi; + + mv $(BUILDDIR)/$(PN).pdf $@ + +$(BUILDDIR): + mkdir $@ -$(PN).aux: $(SRCS) +$(BUILDDIR)/$(PN).aux: $(SRCS) | $(BUILDDIR) $(LATEX) $(PN).tex @@ -102,9 +120,9 @@ $(PN).aux: $(SRCS) # define $BIBS but don't cite anything, you'll run into a similar # problem. Don't do that. # -$(PN).bbl: $(SRCS) | $(PN).aux +$(BUILDDIR)/$(PN).bbl: $(SRCS) | $(BUILDDIR)/$(PN).aux ifdef BIBS - bibtex $(PN).aux + bibtex $(BUILDDIR)/$(PN).aux else printf '' > $@ endif @@ -112,14 +130,14 @@ endif # If the output PDF exists but the log file does not, then an attempt # to "build the log file" (i.e. build the PDF) would do nothing. Thus # whenever the log file does not exist, we do a fresh build. -$(PN).log: $(SRCS) +$(BUILDDIR)/$(PN).log: $(SRCS) $(MAKE) clean $(MAKE) # Ensure that there are no overfull or underfull boxes in the output # document by parsing the log for said warnings. .PHONY: check-boxes -check-boxes: $(PN).log +check-boxes: $(BUILDDIR)/$(PN).log @! grep -i 'overfull\|underfull' $< # Run chktex to find silly mistakes. There is some exit code weirdness @@ -133,7 +151,7 @@ check-chktex: # Ensure that there are no undefined references in the document by # parsing the log file for said warnings. .PHONY: check-undefined -check-undefined: $(PN).log +check-undefined: $(BUILDDIR)/$(PN).log @! grep -i 'undefined' $< # Run a suite of checks. @@ -148,3 +166,4 @@ JUNK_EXTENSIONS += snm spl toc xml .PHONY: clean clean: for ext in $(JUNK_EXTENSIONS); do rm -f *.$$ext; done; + rm -rf $(BUILDDIR)/ -- 2.49.0