Skip to content

Instantly share code, notes, and snippets.

@marrus-sh
Last active May 15, 2019 10:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marrus-sh/ce267187fff0c658c0b4b06b997e5376 to your computer and use it in GitHub Desktop.
Save marrus-sh/ce267187fff0c658c0b4b06b997e5376 to your computer and use it in GitHub Desktop.
Deluxe Makefile for LaTeX
# DOCUMENTATION #
# This makefile greatly simplifies the compilation of LaTeX documents
# into PDFs and the packaging of them into distributions. It has
# special support for the `glossaries` package and is designed to be
# used with larger works, such as textbooks or novels. This makefile
# expects the source directory to look something like this:
#
# * source/
# - 01.tex
# - Makefile
# - Makefile.sty
# - glossary.tex
# - main.tex
# - setup.tex
# - style.cls
#
# (`Makefile.sty` is required unless the `INDEPENDENT` option is set.)
#
# You will notice that glossary data is contained in the external file
# `glossary.tex`. Glossaries are processed using `makeglossaries`, and
# this operation is only performed when `glossary.tex` is updated.
# You can support inline glossaries by defining the main text as a
# glossary prerequisite (see Usage, below).
#
# `style.cls` contains the class definition used for rendering the
# document, and `setup.tex` contains additional preamble information
# only to be used when rendering the full text. `setup.tex` is thus a
# good place to put glossary-handling information. This makefile
# supports rendering texts on both a complete and chapter-by-chapter
# basis; the code for the complete text is in `main.tex` and the code
# for a chapter is in `01.tex`. By default, chapters are expected to
# be named using exactly two digits, although this is configurable.
# Neither chapter nor main source files should contain
# `\begin{document}` as this makefile provides the `document`
# environment itself.
#
# If chapter files are input into the main document using `\include`,
# pagination will be preserved for chapter-only renders. This
# behaviour is implemented through `Makefile.sty`, which redefines
# \include to track the values of counters at the beginning of
# included files. The package option `INDEPENDENT` will leave
# \include unmodified, giving chapter-only renders independent
# pagination.
#
# Note that this makefile can only guarantee the *starting* values of
# counters match; if your `style.cls` treats chapter-by-chapter
# renders differently than the main text, then obviously these values
# will diverge.
#
# Chapter-by-chapter rendering is not required and easily disabled for
# those who do not need it.
#
# By running `make` using only the default settings, a document
# structure like the following will be created:
#
# * chapters/
# - 01.pdf
# * source/
# - 01.tex
# - Makefile
# - Makefile.sty
# - buildfiles/
# + 01.aux
# + 01.log
# + 01.out
# + text.aux
# + text.glg
# + text.glo
# + text.gls
# + text.log
# + text.out
# + text.toc
# + text.xdy
# - glossary.tex
# - main.tex
# - setup.tex
# - style.cls
# * text.pdf
# * text.tar.gz
#
# The makefile compiles the document using multiple passes in order
# to ensure proper pagination and references.
#
# More detailed usage information follows.
#
# - - -
#
# Usage: `make [<args>] [<options>] [<overrides>]`
#
# <args> can be any number of the following values:
# - again : Same as `dist` but remakes the tarball.
# - all : Alias for `dist`.
# - bibliography : Compiles the bibliography. Requires the `BIBLIOGRAPHY` option.
# - buildfiles : Does an initial build but does not copy the text to
# the final destination.
# - chapters : Makes the individual chapters. Will also compile the
# main text unless `INDEPENDENT` is set.
# - clean : Deletes the buildfiles.
# - dist : Creates a .tar.gz containing the full text, individual
# chapters, and the source code. Generates all pdfs in the
# process.
# - distonly : Same as `dist`, but removes individual pdfs after
# generation.
# - everything : Alias for `dist`.
# - glossary : Compiles the glossary.
# - gone : Deletes both the buildfiles and the final output.
# - pdf : Alias for `<name>`.
# - unclean : Deletes the final output but not the buildfiles.
# - text : Alias for `<name>` if `NAME` isn't `text`.
# - <name> : Makes the full text. `<name>` must match the value of
# `NAME`.
# - <chapter> : Makes just the given chapter. There must exist
# a LaTeX file with the given name in the directory, and the
# name of the file must match `CHAPTERPATTERN`. Also compiles the
# main text unless `INDEPENDENT` is set.
#
# If <args> is not provided, this is the same as running `make dist`.
#
# The available <options> are as follows:
# - BIBLIOGRAPHY : Run `biber` as well.
# - NOTEMP : Glossary compilation uses a temporary directory
# (generated using `mktemp -d -t 'gloss'`) in order to support
# file paths which contain Unicode characters. This option
# suppresses this behaviour. Note that there must not be any
# Unicode characters anywhere in the file path if this option is
# chosen. This option has no effect if you aren't using a
# glossary.
# - INDEPENDENT : By default, this makefile slightly modifies the
# `\include` command to ensure consistent pagination for
# chapter-only renders. If you input your chapters in a different
# manner, or aren't interested in maintaining pagination, this
# option leaves `\include` in its original form.
# - VERBOSE : Shows LaTeX log output.
#
# <options> can be set to any non-empty value; for example:
#
# make VERBOSE=1
#
# There are a number of <overrides> which can be used to further
# configure the `make`. These are:
# - BUILDDIR : The name of the folder in which to store the various
# files used for compiling the document. Defaults to
# `buildfiles`. Note that calling `make clean` or `make gone` will
# delete this entire folder.
# - CHAPTERPREFIX : The name of the folder inside of `PREFIX` in
# which to store the chapters. Defaults to `chapters`. Note that
# calling `make unclean` or `make gone` will delete this entire
# folder.
# - CHAPTERPATTERN : The pattern used to identify chapters (and only
# chapters). Defaults to `[0-9][0-9]`. If empty, per-chapter pdf
# creation will be disabled.
# - DOCFILES : Additional documentation files which should be kept
# with the source. Empty by default.
# - GFLAGS : Additional flags to pass to `makeglossaries`. Empty by
# default.
# - GLOSSARY : The name(s) of the external glossary file(s). Glossary
# files should only be defined if you are using the `glossaries`
# package, as this calls `makeglossaries`. Defaults to `glossary`.
# - PREFIX : The final output directory. Defaults to `..`.
# - LATEX : The LaTeX compiler to use. Defaults to `xelatex`.
# - LFLAGS : Additional flags to pass the LaTeX compiler. Empty by
# default.
# - MAIN : The name of the LaTeX file containing the document's
# full contents. Defaults to `main`.
# - NAME : The name of the final document. Defaults to `text`.
# - SETUP : A LaTeX document with preamble commands for use with the
# main document only. Preamble commands intended for both the main
# document and its individual chapters should be included in the
# `STYLE` document.
# - SRCDIR : The location of the source files, including this
# Makefile. Defaults to `.`. You should override this variable
# only if you are calling `make` from another directory. The
# lower-case version `srcdir` is also supported.
# - STYLE : The name(s) of the LaTeX class file(s). Defaults to
# `style`.
#
# All .tex files in the source directory are assumed to be part of
# the document's source. However, only .cls files whose names are
# provided by `STYLE` are tracked. Similarly, only .tex files
# whose names are provided by `GLOSSARY` are considered prerequisites
# for glossary generation.
#
# LICENSE #
# For Makefile:
#
# MIT License
#
# Copyright (c) 2016–2017, 2019 Margaret "Go" Shoemake
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# - - -
#
# For Makefile.sty:
#
# Copyright (c) 1999 2002-2008 LaTeX3 Project
# With slight modifications by Margaret "Go" Shoemake
#
# This work may be distributed and/or modified under the conditions of
# the LaTeX Project Public License, either version 1.3 of this license
# or (at your option) any later version. The latest version of this
# license is in <http://www.latex-project.org/lppl.txt> and version
# 1.3 or later is part of all distributions of LaTeX version
# 2005/12/01 or later.
#
# This work consists of the file Makefile.sty, which is a modified
# excerpt of ltfiles.dtx, included with all LaTeX distributions.
#
SHELL = /bin/sh
# DEFAULT VALUES FOR OVERRIDES #
BUILDDIR = buildfiles
CHAPTERPREFIX = chapters
CHAPTERPATTERN = [0-9][0-9]
DOCFILES =
GLFAGS =
GLOSSARY = glossary
PREFIX = ..
LATEX = xelatex
LFLAGS =
MAIN = main
NAME = text
SETUP = setup
ifdef srcdir
SRCDIR = $(srcdir)
else
SRCDIR = .
endif
STYLE = style
# DECLARATION SETUP #
override prpkgdeclaration = $(if $(INDEPENDENT),,\usepackage{Makefile})
override classdeclaration = $(if $(STYLE),\documentclass{$(STYLE)})
override setupdeclaration = $(if $(SETUP),\input{$(SETUP)})
override prloadeclaration = $(if $(INDEPENDENT),,\makeatletter\@nameuse{cp@$*@pre}\makeatother)
override filesdeclaration = $(if $(INDEPENDENT),,\nofiles)
# DEFAULT MAKE #
everything: dist
# FULL MAKE #
override skeleton = "$(classdeclaration)$(prpkgdeclaration)$(setupdeclaration)\begin{document}\input{$(SRCDIR)/$(MAIN)}\end{document}"
override buildtext = $(if $(VERBOSE),$(LATEX) --jobname=$(NAME) --output-directory=$(BUILDDIR) --file-line-error $(LFLAGS) $(skeleton),$(LATEX) --jobname=$(NAME) --output-directory=$(BUILDDIR) --interaction=batchmode --halt-on-error --file-line-error $(LFLAGS) $(skeleton))
ifneq "$(NAME)" "text"
override nametarget = $(NAME)
else
override nametarget =
endif
$(nametarget) text pdf: $(PREFIX)/$(NAME).pdf
ifdef BIBLIOGRAPHY
ifdef GLOSSARY
$(PREFIX)/$(NAME).pdf: $(BUILDDIR)/$(NAME).gls $(BUILDDIR)/$(NAME).aux $(BUILDDIR)/$(NAME).bib
else
$(PREFIX)/$(NAME).pdf: $(BUILDDIR)/$(NAME).aux $(BUILDDIR)/$(NAME).bib
endif
endif
ifdef GLOSSARY
$(PREFIX)/$(NAME).pdf: $(BUILDDIR)/$(NAME).gls $(BUILDDIR)/$(NAME).aux
else
$(PREFIX)/$(NAME).pdf: $(BUILDDIR)/$(NAME).aux
endif
$(buildtext)
mv -f $(BUILDDIR)/$(NAME).pdf $(PREFIX)/$(NAME).pdf
@echo PDF output generated at $(PREFIX)/$(NAME).pdf
buildfiles: $(BUILDDIR)/$(NAME).aux
$(BUILDDIR)/$(NAME).aux: $(SRCDIR)/*.tex $(addprefix $(SRCDIR)/,$(addsuffix .cls,$(STYLE)))
[[ -d $(BUILDDIR) ]] || mkdir $(BUILDDIR)
$(buildtext)
# BIBLIOGRAPHY MAKE $
bibliography: $(BUILDDIR)/$(NAME).bib
$(BUILDDIR)/$(NAME).bib: $(BUILDDIR)/$(NAME).aux
ifdef BIBLIOGRAPHY
$(if $(VERBOSE),biber $(BUILDDIR)/$(NAME),biber --onlylog $(BUILDDIR)/$(NAME))
endif
# GLOSSARY MAKE #
ifndef NOTEMP
$(BUILDDIR)/$(NAME).gls glossary: glosstempd := $(shell mktemp -d -t 'gloss')
override define buildgloss
mv $(BUILDDIR)/* $(glosstempd)
makeglossaries -d $(glosstempd) $(GFLAGS) $(NAME)
mv $(glosstempd)/* $(BUILDDIR)
rm -rf $(glosstempd)
endef
else
override buildgloss = makeglossaries -d $(BUILDDIR) $(GFLAGS) $(NAME)
endif
glossary: $(BUILDDIR)/$(NAME).gls
$(BUILDDIR)/$(NAME).gls: $(addprefix $(SRCDIR)/,$(addsuffix .tex,$(GLOSSARY)))
ifdef GLOSSARY
[[ -d $(BUILDDIR) ]] || mkdir $(BUILDDIR)
$(buildtext)
$(buildgloss)
$(buildtext)
endif
# CHAPTER-ONLY MAKE #
override chapskeleton = "$(classdeclaration)$(filesdeclaration)\begin{document}$(prloadeclaration)\input{$(SRCDIR)/$*}\end{document}"
override buildchap = $(if $(VERBOSE),$(LATEX) --jobname=$* --output-directory=$(BUILDDIR) --file-line-error $(LFLAGS) $(chapskeleton),$(LATEX) --jobname=$* --output-directory=$(BUILDDIR) --interaction=batchmode --halt-on-error --file-line-error $(LFLAGS) $(chapskeleton))
override chaptersrcs := $(wildcard $(SRCDIR)/$(CHAPTERPATTERN).tex)
override chapternames := $(patsubst $(SRCDIR)/%.tex,%,$(chaptersrcs))
override chapterbuilds := $(patsubst $(SRCDIR)/%.tex,$(BUILDDIR)/%.aux,$(chaptersrcs))
override chapterpdfs := $(patsubst $(SRCDIR)/%.tex,$(PREFIX)/$(CHAPTERPREFIX)/%.pdf,$(chaptersrcs))
chapters: $(chapterpdfs)
$(chapternames): %: $(PREFIX)/$(CHAPTERPREFIX)/%.pdf
$(chapterpdfs): $(PREFIX)/$(CHAPTERPREFIX)/%.pdf: $(BUILDDIR)/%.aux
$(buildchap)
[[ -d $(PREFIX)/$(CHAPTERPREFIX) ]] || mkdir $(PREFIX)/$(CHAPTERPREFIX)
mv -f $(BUILDDIR)/$*.pdf $(PREFIX)/$(CHAPTERPREFIX)/$*.pdf
echo PDF output generated at $(PREFIX)/$(CHAPTERPREFIX)/$*.pdf
ifdef INDEPENDENT
$(chapterbuilds): $(BUILDDIR)/%.aux: $(SRCDIR)/%.tex $(addprefix $(SRCDIR)/,$(addsuffix .cls,$(STYLE)))
[[ -d $(BUILDDIR) ]] || mkdir $(BUILDDIR)
$(buildchap)
else
$(chapterbuilds): $(BUILDDIR)/%.aux: $(PREFIX)/$(NAME).pdf
endif
# DIST #
dist all: $(PREFIX)/$(NAME).tar.gz
$(PREFIX)/$(NAME).tar.gz again: $(PREFIX)/$(NAME).pdf $(chapterpdfs) $(SRCDIR)/*.tex $(addprefix $(SRCDIR)/,$(addsuffix .cls,$(STYLE))) $(if $(DOCFILES),$(SRCDIR)/$(DOCFILES)) $(SRCDIR)/$(lastword $(MAKEFILE_LIST))
mkdir $(NAME)
mkdir $(NAME)/source
mkdir $(NAME)/$(CHAPTERPREFIX)
cp $(PREFIX)/$(NAME).pdf $(NAME)
ifdef chapterpdfs
cp $(chapterpdfs) $(NAME)/$(CHAPTERPREFIX)
endif
cp $(SRCDIR)/*.tex $(addprefix $(SRCDIR)/,$(addsuffix .cls,$(STYLE))) $(if $(DOCFILES),$(SRCDIR)/$(DOCFILES)) $(SRCDIR)/$(lastword $(MAKEFILE_LIST)) $(NAME)/source
tar -czf $(NAME).tar.gz $(NAME)
mv -f $(NAME).tar.gz $(PREFIX)/$(NAME).tar.gz
rm -rf $(NAME)
@echo Tarball created at $(PREFIX)/$(NAME).tar.gz
distonly: dist
rm -rf $(PREFIX)/$(CHAPTERPREFIX)
rm -f $(PREFIX)/$(NAME).pdf
# CLEAN #
clean:
rm -rf $(NAME)
rm -rf $(BUILDDIR)
unclean:
rm -rf $(PREFIX)/$(CHAPTERPREFIX)
rm -f $(PREFIX)/$(NAME).pdf $(PREFIX)/$(NAME).tar.gz
clobber distclean gone: clean unclean
# UNSUPPORTED #
dvi html ps:
# PHONIES #
.PHONY: again clean clobber distclean unclean gone text pdf buildfiles bibliography glossary $(chapternames) dist all distonly $(nametarget)
% From ltfiles.dtx
\def\include#1 {%
\clearpage
\if@filesw
\immediate\write\@mainaux{\string\@input{#1.aux}}%
\fi
\@tempswatrue
\if@partsw
\@tempswafalse
\edef\reserved@b{#1}%
\@for\reserved@a:=\@partlist\do
{\ifx\reserved@a\reserved@b\@tempswatrue\fi}%
\fi
\if@tempswa
\let\@auxout\@partaux
\if@filesw
\immediate\openout\@partaux #1.aux
\immediate\write\@partaux{\relax}%
\fi
\@writeckpt{#1@pre}% % <- Added 2016 by Margaret "Go" Shoemake
\@input@{#1.tex}%
\clearpage
\@writeckpt{#1}%
\if@filesw
\immediate\closeout\@partaux
\fi
\else
\deadcycles\z@
\@nameuse{cp@#1}%
\fi
\let\@auxout\@mainaux}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment