From e7cf90fe30ae5c177527bb2e189c02b7f87de2d6 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 25 Jul 2024 12:16:37 -0400 Subject: [PATCH] GNUmakefile: use a separate build directory This is mainly to support a preview workflow with zathura, which likes to crash or go blank or lose your position in the document during renames. But it's also just nicer, and will probably keep e.g. atril from flickering as well. --- GNUmakefile | 73 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 3669ac2..89bb5d5 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. # @@ -75,8 +88,8 @@ SRCS += $(SAGE_LISTING_DSTS) endif ifdef INDICES -INDEX_SRCS = $(addsuffix .idx,$(INDICES)) -INDEX_DSTS = $(addsuffix .ind,$(INDICES)) +INDEX_SRCS = $(addprefix $(BUILDDIR)/,$(addsuffix .idx,$(INDICES))) +INDEX_DSTS = $(addprefix $(BUILDDIR)/,$(addsuffix .ind,$(INDICES))) endif # The first target is the default, so put the PDF document first. @@ -87,31 +100,32 @@ endif # 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 $(INDEX_DSTS) +# 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 $(INDEX_DSTS) $(LATEX) $(PN).tex - if [ -f $@.previous ] && cmp -s $@ $@.previous; then \ - rm $@.previous; \ - else \ - mv $@ $@.previous; \ - $(REMAKE_INDICES); \ - $(MAKE) $@; \ + if [ -f $@ ]; then \ + while ! cmp -s $@ $(BUILDDIR)/$(PN).pdf; do \ + mv $(BUILDDIR)/$(PN).pdf $@; \ + $(REMAKE_INDICES); \ + $(LATEX) $(PN).tex; \ + done; \ fi; + mv $(BUILDDIR)/$(PN).pdf $@ -$(PN).aux: $(SRCS) +$(BUILDDIR): + mkdir $@ + +$(BUILDDIR)/$(PN).aux: $(SRCS) | $(BUILDDIR) $(LATEX) $(PN).tex @@ -120,7 +134,7 @@ ifdef INDICES # the main $(PN).pdf rule, in order to avoid a chicken-and-egg problem. # This is similar to the $(PN).aux rule above, except that an index is # optional and there might be more than one of them. -$(INDEX_SRCS): $(PN).tex +$(INDEX_SRCS): $(PN).tex | $(BUILDDIR) $(LATEX) $(PN).tex endif @@ -150,9 +164,9 @@ endif # 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 @@ -212,7 +226,7 @@ JUNK_EXTENSIONS += snm spl toc xml .PHONY: clean clean: for ext in $(JUNK_EXTENSIONS); do rm -f *.$$ext; done; - rm -rf dist/ + rm -rf dist/ $(BUILDDIR)/ rm -f $(SAGE_LISTING_DSTS) $(INDEX_SRCS) $(INDEX_DSTS) # If this document will be published, the publisher isn't going to @@ -221,6 +235,7 @@ clean: # will create a "dist" directory and copy the necessary stuff there. # .PHONY: dist -dist: $(PN).bbl +dist: $(BUILDDIR)/$(PN).bbl mkdir -p dist - cp $(SRCS) $(PN).bbl dist/ + cp $(SRCS) $(BUILDDIR)/$(PN).bbl dist/ + -- 2.44.2