Kompilierbefehle

Ein ls -l in einer TeX-Live-2024-Installation liefert die erste Überraschung sofort: latex, der zuerst gelernte LaTeX-Kompilierbefehl, ist gar kein Programm. Es ist ein symbolischer Link auf pdftex, und neunzehn weitere Namen – darunter pdflatex, etex, xmltex und amstex – zeigen auf dieselbe Datei. Welcher Befehl getippt wird, bleibt trotzdem entscheidend, nur nicht aus dem Grund, den die meisten vermuten: Der Name wählt kein anderes Programm, sondern eine andere Formatdatei, und manchmal schrumpft der gesamte Unterschied zwischen zwei Befehlen auf eine einzige ganze Zahl. Diese Seite behandelt die Befehle, die tatsächlich getippt werden – pdflatex, xelatex, lualatex, latex samt dvipdfmx sowie die CJK-Wege platex und uplatex –, dazu die wenigen Optionen, die man wirklich kennen sollte, und das Lesen der Konsole, wenn ein Lauf scheitert.

Wie eine .tex-Datei kompiliert wird und was der Lauf hinterlässt

Eine Zeile genügt: pdflatex document.tex erzeugt document.pdf. Die Endung .tex ist optional, und Optionen stehen immer vor dem Dateinamen. Zurück kommt allerdings nicht nur das PDF. Daneben erscheinen zwei weitere Dateien: document.aux, ein Hauptbuch, das Querverweis- und Inhaltsverzeichnisdaten sammelt, sowie document.log, ein vollständiges Protokoll mit allem, was über den Bildschirm lief, und noch einigem mehr. Beide sind entbehrliche Zwischenprodukte – doch die erste entscheidet darüber, was als Nächstes passiert.

terminal
pdflatex document.tex          # -> document.pdf, document.aux, document.log
lualatex document              # the .tex extension is optional
xelatex -synctex=1 document.tex  # options come before the file name

Wegen dieser .aux-Datei muss ein Kompilierbefehl normalerweise zweimal laufen. LaTeX liest ein Dokument genau einmal von vorne nach hinten; wenn es auf Seite eins das Inhaltsverzeichnis setzt, weiß es noch nicht, auf welcher Seite Abschnitt 7 landen wird. Der erste Lauf schreibt die ermittelten Nummern in .aux, der zweite liest sie zurück und setzt sie in den Text. Literaturverzeichnis und Index verlängern den Umlauf zusätzlich. Wie LaTeX erkennt, dass die Schleife zur Ruhe gekommen ist, und wie latexmk das automatisiert, gehört auf die Seite zu automatischen Builds. Hier geht es um die Befehle, die innerhalb dieser Schleife tatsächlich aufgerufen werden.

latex gegen pdflatex: der Unterschied ist eine ganze Zahl

latex erzeugt .dvi, pdflatex erzeugt .pdf – und doch ist die laufende Binärdatei dieselbe. In TeX Live 2024 lösen beide Links auf pdftex auf, und latex --version meldet sich ungeniert als pdfTeX 3.141592653-2.6-1.40.26 (TeX Live 2024). Der Unterschied steckt nicht im Programm, sondern in der Formatdatei, die jeder Name lädt. pdflatex.ini liest pdftexconfig.tex ein, wo \pdfoutput = 1 gesetzt wird. latex.ini liest genau dieselbe Datei ein und überschreibt den Wert unmittelbar danach mit \pdfoutput=0. Ganz heruntergebrochen trennt diese eine ganze Zahl die beiden Befehle.

terminal
# TeX Live 2024: four commands, three binaries
readlink $(which latex) $(which pdflatex) $(which xelatex) $(which lualatex)
# pdftex
# pdftex
# xetex
# luahbtex

latex --version
# pdfTeX 3.141592653-2.6-1.40.26 (TeX Live 2024)

Woher weiß eine einzige Binärdatei also, welches Format zu laden ist? Sie sieht sich an, unter welchem Namen sie aufgerufen wurde. Der Hilfetext von pdfTeX sagt es unumwunden: Gesucht wird NAME.fmt, wobei NAME der Aufrufname des Programms ist. Wird der Link umbenannt, startet ein anderes LaTeX. Diese Vermutung lässt sich mit -fmt=NAME oder -progname=NAME überschreiben, ebenso mit einer %&format-Zeile ganz oben in der Quelldatei. Genau dieser Kniff erlaubt es, zwanzig verschiedene Namen an die eine ausführbare Datei pdftex zu hängen.

\pdfoutput ist nicht bloß eine Einstellung beim Erzeugen des Formats, sondern ein zur Laufzeit wirksames pdfTeX-Primitiv. Steht \pdfoutput=0 in der allerersten Zeile einer Datei, noch vor \documentclass, liefert selbst ein pdflatex-Lauf eine .dvi-Datei. In der Praxis ist der Weg über die Kommandozeile sauberer: -output-format=dvi oder -output-format=pdf, von pdfTeX und LuaTeX gleichermaßen akzeptiert – nur XeTeX kennt die Option nicht und verwendet stattdessen -no-pdf. Auch LaTeX selbst liest diesen Wert aus und wechselt daraufhin die Grafikbehandlung: im DVI-Modus wird l3backend-dvips.def geladen, im PDF-Modus l3backend-pdftex.def. Genau deshalb nimmt der eine Weg .eps-Abbildungen an und der andere .pdf und .png.

pdflatex, xelatex oder lualatex: die Wahl nach Schriften und Unicode

Ein Kriterium genügt. Ist das Dokument lateinschriftlich und stehen Geschwindigkeit und maximale Paketkompatibilität im Vordergrund, führt pdflatex zum Ziel. Sobald eine bereits im Betriebssystem installierte Schrift beim Namen genannt oder Zeichen jenseits des lateinischen Bereichs gesetzt werden sollen, wechselt man zu xelatex oder lualatex. Alle drei geben PDF aus und nehmen dieselbe .tex-Datei entgegen; völlig verschieden ist nur die Tür, durch die die Schriften hereinkommen.

Warum sind es so viele Befehle geworden? Die Geschichte erklärt es geradlinig. Knuth begann 1978 mit TeX, und dessen Ausgabeformat war DVI – device-independent –, weil PDF, das Adobe 1993 vorstellte, damals schlicht nicht existierte. pdfTeX ist die Erweiterung, die diese Lücke schloss. Ihr Autor Hàn Thế Thành arbeitete in seiner Dissertation an Mikrotypografie: Zeichen dürfen minimal über den rechten Rand hinausragen, Glyphenbreiten werden unmerklich gedehnt, damit der Grauwert der Seite gleichmäßiger wird. Aus derselben Arbeit stammt die direkte PDF-Ausgabe ohne Umweg über DVI. Dass pdflatex heute am schnellsten ist und von den meisten Paketen vorausgesetzt wird, liegt schlicht daran, dass es am längsten im Einsatz ist.

xelatex startet XeTeX, das Jonathan Kew um 2004 entwickelt hat. Mit dem Paket fontspec genügt der Name einer im Betriebssystem vorhandenen OpenType-Schrift, und sie wird verwendet. XeTeX schreibt allerdings kein PDF direkt: Es erzeugt .xdv, eine erweiterte Form von DVI, und übergibt diese an xdvipdfmx, das daraus das PDF macht. -no-pdf hält den Lauf auf der .xdv-Stufe an, -output-driver=CMD tauscht das Konvertierungsprogramm selbst aus. Dass XeTeX als einziges der drei keine Option -output-format kennt, folgt unmittelbar aus dieser Architektur.

In lualatex steckt eine Wendung. In TeX Live 2024 führt der Link nicht zu luatex, sondern zu luahbtex – LuaTeX mit eingebauter Formungsbibliothek HarfBuzz, und genau diese sorgt dafür, dass Schriftsysteme mit komplexen Formungsregeln, darunter Arabisch und die indischen Schriften, korrekt gesetzt werden. Das schlichte luatex gibt es weiterhin; auf es zeigt das unten behandelte dvilualatex. Das Aushängeschild von LuaTeX steht im Namen: ein eingebetteter Lua-Interpreter, mit dem ein Dokument in Zeilenumbruch, Schriftladen und weitere Interna des Satzprogramms eingreifen kann. Stellt man die Versionsnummern nebeneinander, fällt etwas Merkwürdiges auf. tex --version meldet TeX 3.141592653: Knuth nummeriert TeX so, dass mit jeder Aktualisierung eine weitere Stelle der Kreiszahl hinzukommt, und pdfTeX wie XeTeX übernehmen dieses Präfix unverändert. Nur LuaTeX ist aus der Tradition ausgestiegen und nennt sich Version 1.18.0.

BefehlBinärdatei (TeX Live 2024)AusgabeSchriften und Zeichen
pdflatexpdftexPDFTeX-Schriften; am schnellsten, breiteste Paketunterstützung
xelatexxetexPDF (intern über .xdv)OpenType-Systemschriften über fontspec
lualatexluahbtexPDFSystemschriften + HarfBuzz-Formung + Lua-Skripte
latexpdftexDVITeX-Schriften; Weg für EPS-Abbildungen und PSTricks
dvilualatexluatexDVILuaTeX-Funktionen bei nötiger DVI-Ausgabe
platexeuptexDVIJapanisch; EUC-Interna, auf JIS X 0208 begrenzt
uplatexeuptexDVIJapanisch; Unicode-Interna, auch seltene Zeichen

latex und danach dvipdfmx: warum der DVI-Weg überlebt

Zwei Gründe gelten weiterhin. Erstens spricht manche Mechanik nur DVI: Pakete, die über PostScript zeichnen, allen voran PSTricks, entfalten ihre Stärken auf dem Weg von latex zu dvips. Zweitens ist der japanische Satz, Thema des nächsten Abschnitts, traditionell diesen Weg gegangen. latex document.tex schreibt document.dvi, und dvipdfmx document.dvi macht daraus ein PDF; wird PostScript gebraucht, übernimmt dvips. Für den selteneren Wunsch, LuaTeX-Funktionen zu nutzen und dennoch DVI zu erhalten, gibt es dvilualatex, das auf das schlichte luatex ohne HarfBuzz zeigt.

terminal
latex document.tex        # -> document.dvi
dvipdfmx document.dvi     # -> document.pdf
dvips document.dvi        # -> document.ps (for PSTricks and friends)

CJK-Befehle: platex, uplatex und die Alternativen

Japanisch hat eigene Befehle, weil japanischer Satz eigene Regeln hat: vertikale Schreibrichtung, die Kinsoku-Verbote darüber, welche Zeichen eine Zeile beginnen oder beenden dürfen, und der feste Abstand, der zwischen japanischem und lateinischem Text gehört. pTeX hat diese Regeln in die Engine selbst gebaut statt in Makros; das darauf laufende LaTeX heißt pLaTeX und wird mit platex aufgerufen. Die erste Zeile der Formatdatei platex.ini lautet bis heute “for pLaTeX (ASCII Nihongo LaTeX)” – eine Spur der Herkunft bei ASCII. upTeX von Takuji Tanaka erweitert pTeX so, dass der interne Zeichencode vollständiges Unicode ist; LaTeX darauf ist upLaTeX, der Befehl uplatex. Beide schreiben stets DVI und nie direkt PDF.

Dieselbe Überraschung wiederholt sich hier. In TeX Live 2024 sind platex und uplatex beide Links auf eine einzige Binärdatei, euptex, und auch ptex, eptex und uptex laufen dort zusammen. Unterschieden werden sie durch die interne Kanji-Kodierung. platex --version gibt e-upTeX 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.euc) aus, uplatex --version endet auf (utf8.uptex). Es ist also eine einzige ausführbare Datei, die -kanji-internal je nach Aufrufnamen umschaltet. pLaTeX verhält sich wie das klassische pTeX mit EUC-Interna, weshalb die verarbeitbaren Zeichen im Wesentlichen innerhalb von JIS X 0208 bleiben; upLaTeX arbeitet intern mit Unicode und lässt seltene Namenskanji und die vollständigen CJK Unified Ideographs unverändert durch. Genau dieser eine Unterschied macht uplatex zur Standardwahl für ein neues japanisches Dokument. Die Zusammenlegung ist recht jung und genau datiert: Der offizielle, mit TeX Live ausgelieferte pTeX-Leitfaden hält fest, dass platex von TeX Live 2012 bis 2022 auf e-pTeX lief und am 2023-06-01 auf e-upTeX im sogenannten legacy-encoding-compatibility mode umgestellt wurde. Die zusätzlichen upTeX-Primitive stehen seither auch pLaTeX zur Verfügung, während der interne Code japanischer Zeichen bewusst nicht auf Unicode umgestellt wurde, um Abwärtskompatibilität zu wahren.

Die interne Kodierung und die Kodierung der Eingabedatei sind zweierlei. Die Eingabeseite wird mit -kanji=STRING festgelegt und akzeptiert euc, jis, sjis, utf8 oder uptex. Neuere TeX-Live-Versionen setzen UTF-8 voreingestellt, die Angabe kann also oft entfallen – explizit gesetzt bleibt der Build jedoch auch bei wechselnder Umgebung stabil. Damit BOM-loses UTF-8 zuverlässig durchgeht, kommt -no-guess-input-enc hinzu, das die Kodierungserkennung ganz abschaltet. Die Ausgabe ist DVI, den Abschluss übernimmt dvipdfmx.

terminal
# Japanese, the traditional route: typeset -> DVI -> PDF
uplatex -kanji=utf8 -no-guess-input-enc document.tex   # -> document.dvi
dvipdfmx document.dvi                                 # -> document.pdf

Chinesisch und Koreanisch nehmen diesen Weg gar nicht erst. Beide werden üblicherweise einer Unicode-nativen Engine übergeben: für Chinesisch xelatex oder lualatex mit dem Bündel ctex, das darunter xeCJK und Verwandte aufruft; für Koreanisch dieselben Engines mit kotex. Für Japanisch besteht dieselbe Möglichkeit – wird luatexja unter lualatex geladen, entsteht das PDF unmittelbar. Auf diesem Weg entfällt -kanji: Eine durchgehend auf Unicode gebaute Engine hat keine interne Kodierung mehr, die sich umschalten ließe.

Die lohnenden Optionen: -interaction=nonstopmode, -halt-on-error, -output-directory

Optionen stehen stets vor dem Dateinamen, und die folgenden funktionieren mit jedem der Befehle von pdfTeX, XeTeX und LuaTeX. Vier davon verdienen sich täglich ihren Platz: -synctex=1 für die Editoranbindung, -interaction=nonstopmode, damit ein Lauf nicht hängen bleibt, -halt-on-error, um umgekehrt beim ersten Problem abzubrechen, und -file-line-error, das die Meldung in eine maschinenlesbare Form bringt.

OptionWirkung
-synctex=1Schreibt document.synctex.gz und ermöglicht Sprünge zwischen Editor und PDF
-interaction=nonstopmodeLäuft bei Fehlern bis zum Ende weiter, statt auf Eingabe zu warten; batchmode unterdrückt zusätzlich die Terminalausgabe
-halt-on-errorBricht beim allerersten Fehler ab; es entsteht kein PDF
-file-line-errorFormt den Meldungskopf zu ./document.tex:3: um, was IDEs und CI auswerten können
-output-directory=DIRSchreibt Ausgabe und Hilfsdateien nach DIR; DIR muss vorher existieren
-jobname=NAMELegt den Basisnamen aller Ausgabedateien vor der Endung fest
-draftmodeLäuft ohne PDF-Ausgabe (pdfTeX / LuaTeX); nützlich für Zwischenläufe, die nur Verweise festlegen
-output-format=FORMATWählt dvi oder pdf (nur pdfTeX und LuaTeX; XeTeX verwendet -no-pdf)
-shell-escapeHebt alle Beschränkungen für externe Befehle über \write18 auf (die Warnung im nächsten Abschnitt beachten)
terminal
pdflatex -synctex=1 -interaction=nonstopmode -halt-on-error -file-line-error document.tex

mkdir -p build   # -output-directory will NOT create it for you
pdflatex -output-directory=build document.tex

-output-directory birgt eine Falle, in die CI-Pipelines ständig tappen: Das angegebene Verzeichnis muss bereits existieren. Der Hilfetext von pdfTeX sagt genau das – es verwendet ein vorhandenes DIR. Fehlt es, meldet der Lauf zunächst “Please type another transcript file name” und endet dann mit ! Emergency stop und “Fatal error occurred, no output PDF file produced!”. Da die Ursache nichts mit dem Satz zu tun hat, stolpert selbst darüber, wer LaTeX-Logs flüssig liest. Ein mkdir -p in der Zeile davor behebt alles.

-shell-escape: warum minted es braucht und warum es gefährlich ist

Diese Option gewährt dem Dokument das Recht, beliebige Shell-Befehle auf dem eigenen Rechner auszuführen. Ganz verschlossen sind externe Befehle standardmäßig allerdings nicht. TeX Live läuft in einem eingeschränkten Modus und gibt bei jedem Lauf die Zeile restricted \write18 enabled. aus. In diesem Zustand darf \write18 nur Programme aufrufen, die in texmf.cnf auf einer Erlaubnisliste stehen, und in TeX Live 2024 ist diese Liste kurz: bibtex, bibtex8, extractbb, gregorio, kpsewhich, makeindex, memoize-extract.pl, memoize-extract.py, repstopdf, r-mpost, texosquery-jre8. Dass Literaturverzeichnis und Index ganz ohne Optionen funktionieren, liegt genau daran, dass diese beiden Einträge von vornherein erlaubt sind.

pygmentize steht nicht auf dieser Liste. texmf.cnf lässt es bewusst weg und versieht das mit einem Kommentar, der die Sicherheit seiner Filterfunktion in Frage stellt. minted, das Quelltext einfärbt, ruft genau dieses Programm auf – in eingeschränktem Modus funktioniert es also nicht, und nur volles -shell-escape hilft. Voll heißt dabei wörtlich voll: Eine von jemand anderem erhaltene .tex-Datei kann in dieser einen Kompilierung Dateien löschen, lokale Daten nach außen schicken oder etwas installieren. Die Regel darf einfach bleiben – nur für selbst geschriebene Dokumente in einem selbst kontrollierten Verzeichnis aktivieren. Niemals für eine heruntergeladene Vorlage oder eine zur Begutachtung eingegangene Einreichung.

terminal
# minted calls pygmentize, which the restricted allow-list does not include
pdflatex -shell-escape document.tex

# turn it off explicitly when compiling a file you did not write
pdflatex -no-shell-escape untrusted.tex

Die Konsolenausgabe lesen, wenn eine Kompilierung scheitert

Gelesen wird ab der ersten Zeile, die mit ! beginnt, nicht vom Ende her. LaTeX-Fehler pflanzen sich fort, und was am Schluss auf dem Bildschirm steht, ist meist Folgeschaden des ersten Fehlers; die Ursache steht weiter oben. Jede Fehlermeldung hat dieselbe Gestalt: Die !-Zeile benennt das Symptom, die darunterliegende Zeile mit l. zeigt die Stelle.

console
! Missing $ inserted.
<inserted text>
                $
l.3 Some text with a bare x^
                            2 here.
?

Entscheidend ist die Zeile l.3. Sie bedeutet Quellzeile 3, wird aber genau an der Stelle in zwei Teile gebrochen ausgegeben, bis zu der TeX gelesen hatte. Alles vor dem Bruch ist verarbeitet, alles danach noch ungelesen. Hier fällt der Bruch unmittelbar hinter x^, womit das Hochstellungszeichen sichtbar als Verursacher dasteht. ! Undefined control sequence. folgt demselben Muster, und der falsch geschriebene Befehl direkt vor dem Bruch ist bereits die Antwort. Das abschließende ? ist eine Eingabeaufforderung: Der Lauf steht im voreingestellten errorstopmode und wartet. Mit Enter geht es weiter, mit x wird abgebrochen.

Genau dieser Dialog ist in Skripten und CI unerwünscht, wofür die Interaktionsmodi da sind. -interaction=nonstopmode gibt alles ohne Halt aus, batchmode unterdrückt zusätzlich die Terminalausgabe, und scrollmode fragt nur nach, wenn eine Datei nicht gefunden wird. Soll umgekehrt nur das erste Problem sichtbar werden, beendet -halt-on-error den Lauf mit ! Emergency stop. und “Fatal error occurred, no output PDF file produced!”. Ergänzt -file-line-error den Aufruf, lautet der Kopf ./document.tex:3: Missing $ inserted., was Editoren und CI in einen anklickbaren Verweis verwandeln. Was auch immer gewählt wird: Das vollständige Protokoll landet stets in .log – wer es im Terminal verpasst, findet denselben Text dort wieder.

Welcher Kompilierbefehl ist der richtige

  • Ein lateinschriftliches Dokumentpdflatex. Am schnellsten und die Voreinstellung, die die meisten Pakete annehmen.
  • Eine Schrift des Betriebssystems soll beim Namen genannt werdenxelatex oder lualatex, beide über fontspec.
  • Schriftsysteme mit komplexer Formung oder Skripting des Satzprogrammslualatex, faktisch luahbtex mit HarfBuzz.
  • Ein neues japanisches Dokumentuplatex und danach dvipdfmx, oder lualatex mit luatexja.
  • Chinesisch oder Koreanischxelatex oder lualatex mit ctex beziehungsweise kotex, ganz ohne DVI-Stufe.
  • PSTricks und andere reine DVI-Mechaniklatex und danach dvips oder dvipdfmx.

Zum Schluss eine Diagnosegewohnheit. Scheitert der Build-Knopf im Editor, wird derselbe Befehl zuerst von Hand im Terminal getippt. Läuft er dort durch, liegt das Problem an der Editorkonfiguration und nicht am Dokument. Bevor eine Datei weitergegeben oder in die CI gestellt wird, empfiehlt sich ein Lauf mit -halt-on-error -file-line-error -interaction=nonstopmode, damit die erste echte Fehlerstelle lesbar ist. Im Alltag tippt diese Befehle allerdings kaum jemand zweimal von Hand – die Arbeit übernimmt latexmk, das die Läufe zählt und dvipdfmx selbst aufruft. Woran es erkennt, wann Schluss ist, behandelt die Seite zu automatischen Builds.