Skip to content

1. minimath

nguyenvukhang edited this page Oct 21, 2024 · 1 revision

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 minimath binary (written in Rust).
    • CLI interface by clap.
    • Configured with YAML.
    • Development server (for live previews).
    • Automatic label generation.
    • Pretty-prints pdflatex output.
  • 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.

Core compilation flow

  1. The user selects a preset to compile. If none is specified, minimath compiles everything.
  2. Spawn a child process of pdflatex and keep the handle on its stdin.
  3. Traverse the *.tex files across the project based on the preset and write content directly to pdflatex's stdin.
  4. Write build artifacts to the .build directory and move the generated PDF file to the current working directory.

The machinery that orchestrates all of this is the minimath binary.

Interacting with pdfTeX

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.tex

to 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

pdflatex

It 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.

 

< Prev          Next >
Clone this wiki locally