]> gitweb.michael.orlitzky.com - mjotex.git/blob - GNUmakefile
GNUmakefile: use a separate build directory
[mjotex.git] / GNUmakefile
1 #
2 # Example makefile using mjotex and a BibTeX references database.
3 #
4 # After defining $(PN) to be the name of your document, this will
5 # compile the source file $(PN).tex to $(PN).pdf.
6 #
7 # To support workflows where the document is kept open in a PDF reader
8 # during recompilation, the build process takes place in a separate
9 # $(BUILDDIR) directory that defaults to "build". Only when the build
10 # has completed do we move the resulting $(PN).pdf to the current
11 # directory. This avoids renaming or modifying the open document in
12 # place, which in turn helps prevent flickering, loss of bookmarks, et
13 # cetera, in several PDF readers.
14
15 # The build directory. Not broken? Don't fix.
16 BUILDDIR=build
17
18 # The latex compiler. The SOURCE_DATE_EPOCH=0 prevents the creation
19 # and modification dates from being embedded as metadata into the
20 # output file; that in turn is important because it allows us to tell
21 # when the output stops changing (that is, when we are done). The
22 # variable is supported in pdftex v1.40.17 and later.
23 LATEX = SOURCE_DATE_EPOCH=0 pdflatex -file-line-error -halt-on-error --output-directory $(BUILDDIR)
24
25 # The name of this document.
26 #
27 # For example, to use the name of our parent directory:
28 #
29 # PN = $(notdir $(realpath .))
30 #
31 PN = examples
32
33 # A space-separated list of bib files. These must all belong to paths
34 # contained in your $BIBINPUTS environment variable.
35 #
36 # Leave commented if you don't use a bibliography database.
37 #
38 BIBS = local-references.bib
39
40 # A space-separated list of the mjotex files that you use. The path to
41 # mjotex must be contain in your $TEXINPUTS environment variable.
42 #
43 # MJOTEX = mjotex.sty
44 #
45 MJOTEX = mjo-algebra.tex mjo-algorithm.tex mjo-arrow.tex mjo-calculus.tex
46 MJOTEX += mjo-common.tex mjo-complex.tex mjo-cone.tex mjo-convex.tex
47 MJOTEX += mjo-eja.tex mjo-font.tex mjo-hurwitz.tex mjo-linear_algebra.tex
48 MJOTEX += mjo-listing.tex mjo-proof_by_cases.tex mjo-set.tex mjo-theorem.tex
49 MJOTEX += mjo-theorem-star.tex mjo-topology.tex mjo.bst
50
51 # Compile a list of raw source code listings (*.listing) and their
52 # associated output files (*.py) that will be tested by check-sage.
53 SAGE_LISTING_SRCS = $(wildcard sage_listings/*.listing)
54 SAGE_LISTING_DSTS = $(patsubst %.listing,%.py,$(SAGE_LISTING_SRCS))
55
56 # A space-separated list of indices (just their names). Usually you'll
57 # have just one, and it will be named the same thing as your document,
58 # because that's what the makeidx package does.
59 #
60 # Leave commented if you don't use an index.
61 #
62 INDICES = $(PN)
63
64 # We have to rebuild the index whenever the contents of the document
65 # change, because page numbers get moved around. But when no INDICES
66 # are defined, rebuilding them should be a no-op. This next definition
67 # ensures that.
68 ifdef INDICES
69 REMAKE_INDICES = makeindex $(INDEX_SRCS)
70 else
71 REMAKE_INDICES = true
72 endif
73
74 # Use kpsewhich (from the kpathsea suite) to find the absolute paths
75 # of the bibtex/mjotex files listed in in $(BIBS)/$(MJOTEX). The SRCS
76 # variable should contain all (Bib)TeX source files for the document.
77 SRCS = $(PN).tex
78 ifdef BIBS
79 BIBPATHS = $(shell kpsewhich $(BIBS))
80 SRCS += $(BIBPATHS)
81 endif
82 ifdef MJOTEX
83 MJOTEXPATHS = $(shell kpsewhich $(MJOTEX))
84 SRCS += $(MJOTEXPATHS)
85 endif
86 ifdef SAGE_LISTING_DSTS
87 SRCS += $(SAGE_LISTING_DSTS)
88 endif
89
90 ifdef INDICES
91 INDEX_SRCS = $(addprefix $(BUILDDIR)/,$(addsuffix .idx,$(INDICES)))
92 INDEX_DSTS = $(addprefix $(BUILDDIR)/,$(addsuffix .ind,$(INDICES)))
93 endif
94
95 # The first target is the default, so put the PDF document first.
96 #
97 # This voodoo is all designed to find a "fixed point" of calling
98 # $(LATEX). When you build a LaTeX document, it requires an unknown
99 # number of compilation passes. How do you know when to stop? Easy,
100 # stop when the output file stops changing! But how to encode that
101 # in a makefile?
102 #
103 # At the start of this rule, we call $(LATEX) to compile $(PN).tex.
104 # It stores the resulting PDF in a separate "build" directory, so this
105 # will not actually create or overwrite the target $(PN).pdf. If there
106 # is no $(PN).pdf already, then we rename the new one to $(PN).pdf and
107 # we are done. But if there was a previous version, then we compare
108 # the two (new & old) versions. In either case, we rename the new one
109 # over the old one. But if the two differ, then we repeat this process
110 # in a loop until the just-built PDF is identical to the one from the
111 # previous iteration.
112 $(PN).pdf: $(SRCS) $(BUILDDIR)/$(PN).bbl $(INDEX_DSTS)
113 $(LATEX) $(PN).tex
114
115 if [ -f $@ ]; then \
116 while ! cmp -s $@ $(BUILDDIR)/$(PN).pdf; do \
117 mv $(BUILDDIR)/$(PN).pdf $@; \
118 $(REMAKE_INDICES); \
119 $(LATEX) $(PN).tex; \
120 done; \
121 fi;
122
123 mv $(BUILDDIR)/$(PN).pdf $@
124
125 $(BUILDDIR):
126 mkdir $@
127
128 $(BUILDDIR)/$(PN).aux: $(SRCS) | $(BUILDDIR)
129 $(LATEX) $(PN).tex
130
131
132 ifdef INDICES
133 # We need to be able to build the index source files without involving
134 # the main $(PN).pdf rule, in order to avoid a chicken-and-egg problem.
135 # This is similar to the $(PN).aux rule above, except that an index is
136 # optional and there might be more than one of them.
137 $(INDEX_SRCS): $(PN).tex | $(BUILDDIR)
138 $(LATEX) $(PN).tex
139 endif
140
141 ifdef INDICES
142 # Create real indices from source files by running "makeindex" on
143 # them. We depend on SRCS here because we *do* want to rebuild the
144 # index if the source document changes, but we use an order-only
145 # dependency (see the bbl rule below) on the idx files to prevent us
146 # from going into a rebuild loop when the idx files are regenerated.
147 %.ind: $(SRCS) | %.idx
148 makeindex $|
149 endif
150
151 # The pipe below indicates an "order-only dependency" on the aux file.
152 # Without it, every compilation of $(PN).tex would produce a new
153 # $(PN).aux, and thus $(PN).bbl would be rebuilt. This in turn causes
154 # $(PN).pdf to appear out-of-date, which leads to a recompilation of
155 # $(PN).tex... and so on. The order-only dependency means we won't
156 # rebuild $(PN).bbl if $(PN).aux changes.
157 #
158 # As a side effect, we now need to depend on $(SRCS) here, since we
159 # won't pick it up transitively from $(PN).aux.
160 #
161 # If the $BIBS variable is undefined, we presume that there are no
162 # references and create an empty bbl file. Otherwise, we risk trying
163 # to run biblatex on an aux file containing no citations. If you do
164 # define $BIBS but don't cite anything, you'll run into a similar
165 # problem. Don't do that.
166 #
167 $(BUILDDIR)/$(PN).bbl: $(SRCS) | $(BUILDDIR)/$(PN).aux
168 ifdef BIBS
169 bibtex $(BUILDDIR)/$(PN).aux
170 else
171 printf '' > $@
172 endif
173
174 # If the output PDF exists but the log file does not, then an attempt
175 # to "build the log file" (i.e. build the PDF) would do nothing. Thus
176 # whenever the log file does not exist, we do a fresh build.
177 $(PN).log: $(SRCS)
178 $(MAKE) clean
179 $(MAKE)
180
181 # How do we convert a raw listing into something testable by sage? We
182 # append/prepend triple quotes to make the whole thing into a doctest,
183 # and then we replace any blank lines by "<BLANKLINE>".
184 sage_listings/%.py: sage_listings/%.listing
185 echo '"""' > $@ && cat $< >> $@ && echo '"""' >> $@ && sed -i 's/^[[:space:]]*$$/<BLANKLINE>/' $@
186
187 # Ensure that there are no overfull or underfull boxes in the output
188 # document by parsing the log for said warnings.
189 .PHONY: check-boxes
190 check-boxes: $(PN).log
191 @! grep -i 'overfull\|underfull' $<
192
193 # Run chktex to find silly mistakes. There is some exit code weirdness
194 # (Savannah bug 53129), so we just look for empty output.
195 .PHONY: check-chktex
196 CHKTEX = chktex --localrc .chktexrc --quiet --inputfiles=0
197 check-chktex:
198 @chktexout=$$($(CHKTEX) $(PN).tex); \
199 test -z "$${chktexout}" || { echo "$${chktexout}" 1>&2; exit 1; }
200
201 # Ensure that there are no undefined references in the document by
202 # parsing the log file for said warnings.
203 .PHONY: check-undefined
204 check-undefined: $(PN).log
205 @! grep -i 'undefined' $<
206
207 # Use sage to doctest any \sagelisting{}s in SAGE_LISTING_DSTS.
208 # The actuall command is ifdef'd so that we can comment out
209 # the definition of SAGE_LISTING_DSTS without breaking the
210 # default definition of the "check" target.
211 .PHONY: check-sage
212 check-sage: $(SAGE_LISTING_DSTS)
213 ifdef SAGE_LISTING_DSTS
214 sage -t --timeout=0 $^
215 endif
216
217 # Run a suite of checks.
218 .PHONY: check
219 check: check-boxes check-chktex check-undefined check-sage
220
221 # Clean up leftover junk. This only looks overcomplicated because
222 # the *.{foo,bar} syntax supported by Bash is not POSIX, and Make
223 # will execute these commands using /bin/sh (which should be POSIX).
224 JUNK_EXTENSIONS = aux bbl bcf blg glo ilg ist listing lof log nav out pdf
225 JUNK_EXTENSIONS += snm spl toc xml
226 .PHONY: clean
227 clean:
228 for ext in $(JUNK_EXTENSIONS); do rm -f *.$$ext; done;
229 rm -rf dist/ $(BUILDDIR)/
230 rm -f $(SAGE_LISTING_DSTS) $(INDEX_SRCS) $(INDEX_DSTS)
231
232 # If this document will be published, the publisher isn't going to
233 # have your BibTeX database or your mjotex files. So, you need to
234 # package them up along with the code for your document. This target
235 # will create a "dist" directory and copy the necessary stuff there.
236 #
237 .PHONY: dist
238 dist: $(BUILDDIR)/$(PN).bbl
239 mkdir -p dist
240 cp $(SRCS) $(BUILDDIR)/$(PN).bbl dist/
241