-
Notifications
You must be signed in to change notification settings - Fork 124
Add PDF build via Sphinx + XeLaTeX #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| # Building the book as a PDF | ||
|
|
||
| The book is a Sphinx + MyST-Markdown project that normally builds to **HTML** | ||
| (`sphinx-build -b html . _build/html`). This doc explains how to also produce a | ||
| **PDF** via the LaTeX builder. | ||
|
|
||
| > TL;DR — once prerequisites are installed: | ||
| > ```bash | ||
| > ./scripts/build-pdf.sh | ||
| > open _build/latex/moderngpuprogrammingformlsys.pdf | ||
| > ``` | ||
|
|
||
| ## How it works | ||
|
|
||
| `Sphinx (LaTeX builder) -> .tex -> xelatex (latexmk) -> PDF` | ||
|
|
||
| We use **XeLaTeX**, not the default pdfLaTeX, because the text contains Unicode | ||
| symbols (`≈ × ≤ → …`) that pdfLaTeX cannot typeset. SVG figures are converted to | ||
| PDF on the fly via `rsvg-convert`. | ||
|
|
||
| `conf.py` already contains the needed settings: | ||
|
|
||
| ```python | ||
| latex_engine = "xelatex" | ||
| latex_elements = { | ||
| "fontpkg": r""" | ||
| \setmainfont{texgyretermes-regular.otf}[ ... ] | ||
| \setsansfont{texgyreheros-regular.otf}[ ... ] | ||
| \setmonofont{texgyrecursor-regular.otf}[ ... ] | ||
| """, | ||
| } | ||
| # extensions list also includes "sphinxcontrib.rsvgconverter" | ||
| ``` | ||
|
|
||
| The tex-gyre fonts are referenced **by OTF filename** because a minimal TeX | ||
| install (BasicTeX) doesn't ship Sphinx's default GNU FreeFont, and the font | ||
| database doesn't always resolve tex-gyre by family name. | ||
|
|
||
| ## Prerequisites (one-time) | ||
|
|
||
| These need admin rights (`brew`, `sudo tlmgr`) and a fair amount of download. | ||
|
|
||
| ### 1. Python build deps | ||
| ```bash | ||
| pip install sphinx myst-parser sphinx-copybutton sphinxcontrib-svg2pdfconverter | ||
| ``` | ||
|
|
||
| ### 2. A TeX distribution (provides xelatex + latexmk) | ||
| ```bash | ||
| brew install --cask basictex # ~100 MB minimal TeX (or 'mactex' for the full ~5 GB) | ||
| # put TeX on PATH for the current shell: | ||
| eval "$(/usr/libexec/path_helper)" | ||
| export PATH="/Library/TeX/texbin:$PATH" | ||
| ``` | ||
|
|
||
| ### 3. LaTeX packages Sphinx's output needs | ||
| ```bash | ||
| sudo tlmgr update --self | ||
| sudo tlmgr install latexmk tex-gyre fncychap wrapfig capt-of needspace \ | ||
| tabulary varwidth titlesec framed upquote | ||
| ``` | ||
| If a later build complains `LaTeX Error: File 'xxx.sty' not found`, install it: | ||
| `sudo tlmgr install xxx`. | ||
|
|
||
| ### 4. SVG -> PDF converter (for the figures) | ||
| ```bash | ||
| brew install librsvg # provides rsvg-convert | ||
| ``` | ||
|
|
||
| ## Build | ||
|
|
||
| ```bash | ||
| ./scripts/build-pdf.sh | ||
| ``` | ||
|
|
||
| or manually: | ||
|
|
||
| ```bash | ||
| export PATH="/Library/TeX/texbin:$PATH" | ||
| sphinx-build -b latex . _build/latex | ||
| cd _build/latex && make # latexmk drives xelatex (multiple passes for TOC/refs) | ||
| ``` | ||
|
|
||
| **Output:** `_build/latex/moderngpuprogrammingformlsys.pdf` | ||
|
|
||
| `_build/` is gitignored, so the PDF is a local artifact — it is not committed. | ||
|
|
||
| ## Known limitations of the PDF | ||
|
|
||
| 1. **Interactive demos are missing.** The book embeds self-contained HTML/JS | ||
| slide demos via `<iframe>` (the `_extra/` content + `html_extra_path`). These | ||
| are live web content and **cannot render in a PDF** — expect blank/absent | ||
| regions where they appear in the HTML. | ||
| 2. **Some box-drawing / special glyphs may be missing.** The build logs | ||
| `Missing character` warnings for glyphs like `─` (U+2500) used in some | ||
| ASCII-art / code blocks, because the tex-gyre fonts lack them. The PDF still | ||
| builds; those glyphs just render as gaps. To recover them, add a Unicode-rich | ||
| monospace fallback in `conf.py`'s `fontpkg` (e.g. DejaVu Sans Mono / Symbola). | ||
| 3. **First-pass reference warnings are normal.** "Latex failed to resolve N | ||
| reference(s)" appears mid-build; latexmk re-runs to resolve them. Only a | ||
| non-zero final exit / "no output PDF" indicates a real failure — check | ||
| `_build/latex/moderngpuprogrammingformlsys.log`. | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| | Symptom in the `.log` | Fix | | ||
| | --- | --- | | ||
| | `Unicode character ... not set up for use with LaTeX` | Ensure `latex_engine = "xelatex"` (not pdflatex). | | ||
| | `fontspec Error: The font "..." cannot be found` | Use the tex-gyre **OTF filenames** (as in `conf.py`), or `sudo tlmgr install tex-gyre`. | | ||
| | `File 'xxx.sty' not found` | `sudo tlmgr install xxx`. | | ||
| | SVG figure errors / blank figures | `brew install librsvg` and confirm `sphinxcontrib.rsvgconverter` is in `extensions`. | | ||
|
|
||
| ## Note on conf.py | ||
|
|
||
| `conf.py` currently defines `extensions = [...]` **twice** — the second | ||
| assignment (which adds `sphinxcontrib.rsvgconverter`) wins. It works, but is | ||
| fragile; consider consolidating into a single `extensions` list. | ||
|
Comment on lines
+113
to
+117
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||
| # | ||||||||||||||
| # build-pdf.sh — build the book as a PDF via Sphinx -> XeLaTeX. | ||||||||||||||
| # | ||||||||||||||
| # Run from the repo root: ./scripts/build-pdf.sh | ||||||||||||||
| # Output: _build/latex/moderngpuprogrammingformlsys.pdf | ||||||||||||||
| # | ||||||||||||||
| # Prerequisites (one-time, need admin/brew — see README "PDF build"): | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||
| # - MacTeX/BasicTeX (xelatex, latexmk) on PATH (/Library/TeX/texbin) | ||||||||||||||
| # - librsvg (rsvg-convert) for the SVG figures: brew install librsvg | ||||||||||||||
| # - LaTeX packages: sudo tlmgr install latexmk tex-gyre fncychap wrapfig \ | ||||||||||||||
| # capt-of needspace tabulary varwidth titlesec framed upquote | ||||||||||||||
| # - Python deps: pip install sphinx myst-parser sphinx-copybutton \ | ||||||||||||||
| # sphinxcontrib-svg2pdfconverter | ||||||||||||||
| # | ||||||||||||||
| # conf.py already sets: latex_engine="xelatex" + tex-gyre OTF fonts (BasicTeX | ||||||||||||||
| # lacks Sphinx's default FreeFont), and loads sphinxcontrib.rsvgconverter for SVGs. | ||||||||||||||
| set -euo pipefail | ||||||||||||||
|
|
||||||||||||||
| REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" | ||||||||||||||
| cd "$REPO_ROOT" | ||||||||||||||
|
|
||||||||||||||
| # Make sure the TeX toolchain is reachable even from a fresh shell. | ||||||||||||||
| export PATH="/Library/TeX/texbin:$PATH" | ||||||||||||||
|
|
||||||||||||||
| PDF="_build/latex/moderngpuprogrammingformlsys.pdf" | ||||||||||||||
|
|
||||||||||||||
| echo "==> Checking toolchain" | ||||||||||||||
| for bin in sphinx-build xelatex latexmk rsvg-convert; do | ||||||||||||||
| if ! command -v "$bin" >/dev/null 2>&1; then | ||||||||||||||
| echo "ERROR: '$bin' not found on PATH. See README 'PDF build' prerequisites." >&2 | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update the error message to reference
Suggested change
|
||||||||||||||
| exit 1 | ||||||||||||||
| fi | ||||||||||||||
| done | ||||||||||||||
|
|
||||||||||||||
| echo "==> 1/2 Generating LaTeX from Sphinx sources" | ||||||||||||||
| sphinx-build -b latex . _build/latex | ||||||||||||||
|
|
||||||||||||||
| echo "==> 2/2 Compiling LaTeX -> PDF (xelatex via latexmk)" | ||||||||||||||
| ( cd _build/latex && latexmk -C >/dev/null 2>&1 || true; make ) | ||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using a semicolon
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| if [[ -f "$PDF" ]]; then | ||||||||||||||
| echo | ||||||||||||||
| echo "==> Done: $REPO_ROOT/$PDF" | ||||||||||||||
| echo " (Open with: open \"$REPO_ROOT/$PDF\")" | ||||||||||||||
| else | ||||||||||||||
| echo "ERROR: PDF was not produced. Check _build/latex/moderngpuprogrammingformlsys.log" >&2 | ||||||||||||||
| exit 1 | ||||||||||||||
| fi | ||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of redefining the entire
extensionslist (which was already defined on line 34), append the new extension to the existing list to avoid duplication and keep the configuration clean.