-
Notifications
You must be signed in to change notification settings - Fork 0
1. minimath
While this project ultimately compiles down to just a single PDF, the supporting infrastructure is very comprehensive, one that I've been working on in parallel with the book for a year. Here are its components:
- The
minimathbinary (written in Rust). -
texlive-small: a Docker image (built on GitHub Actions and hosted on GHCR) -
minimath-rg: a ripgrep-inspired indexer. - Build + Test + Compile PDF + Publish on GitHub Actions.
- Formatted with latexindent.
- The user selects a preset to compile. If
none is specified,
minimathcompiles everything. - Spawn a child process of
pdflatexand keep the handle on its stdin. - Traverse the
*.texfiles across the project based on the preset and write content directly topdflatex's stdin. - Write build artifacts to the
.builddirectory and move the generated PDF file to the current working directory.
The machinery that orchestrates all of this is the minimath binary.
After installing a copy/distribution of LaTeX, the simplest way to compile a PDF
from plain-source TeX is to write all your TeX into one file, say
one-shot-job.tex:
\documentclass{article}
\begin{document}
Khang was here.
\end{document}and then run the command
pdflatex one-shot-job.texto produce a one-shot-job.pdf file (That example above actually works).
Now, when pdflatex is ran without a path as argument, it will interpret all
remaining commands as TeX input. To see how this works, try running just
pdflatexIt will enter a REPL that looks like this,
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) (preloaded format=pdflatex)
restricted \write18 enabled.
**
where you can start typing in what would have been the contents of
one-shot-job.tex. After you've done all that, the screen should look something
like this:
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) (preloaded format=pdflatex)
restricted \write18 enabled.
**\documentclass{article}
entering extended mode
LaTeX2e <2023-11-01> patch level 1
L3 programming layer <2024-02-20>
*\begin{document}
(/usr/local/texlive/2024basic/texmf-dist/tex/latex/base/article.cls
Document Class: article 2023/05/17 v1.4n Standard LaTeX document class
(/usr/local/texlive/2024basic/texmf-dist/tex/latex/base/size10.clo))
(/usr/local/texlive/2024basic/texmf-dist/tex/latex/l3backend/l3backend-pdftex.d
ef)
No file texput.aux.
*Khang was here
*\end{document}
[1\{/usr/local/texlive/2024basic/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
(./texput.aux)</usr/local/texlive/2024basic/texmf-dist/fonts/type1/public/amsfo
nts/cm/cmr10.pfb>
Output written on texput.pdf (1 page, 13532 bytes).
Transcript written on texput.log.
and you'd find a texput.pdf existing in the current directory
that should match the previously generated one-shot-job.pdf exactly. The core
compilation flow of minimath exploits this behavior
of pdflatex.
We use Rust standard library's Command to spawn a pdflatex
subprocess and keep it open as we write to its stdin. Then, instead of us typing
the contents of the .tex document line-by-line, we can now programmatically
send characters to the subprocess. It is through this and a strategic traversal
of all the *.tex files in the repository that we build the final PDF.
There's just one more thing: in the spirit of
reproducibility, we've downloaded a minimal set of
packages and committed them to this repository at .github/tex/*.sty. But how
will pdflatex know to look in there for TeX packages? The linux
documentation tells us to set the TEXINPUTS environment
variable to .github/tex: like so
TEXINPUTS=.github/tex: pdflatex ...and we're all set.