Commandes de compilation

Un simple ls -l dans une installation TeX Live 2024 réserve tout de suite une surprise : latex, la commande de compilation LaTeX que tout le monde apprend en premier, n’est pas un programme. C’est un lien symbolique vers pdftex, et dix-neuf autres noms — dont pdflatex, etex, xmltex et amstex — désignent ce même fichier unique. La commande que l’on tape reste pourtant décisive, mais pas pour la raison que l’on imagine : le nom ne choisit pas un autre programme, il choisit un autre fichier de format, et parfois toute la différence entre deux commandes tient à un seul nombre entier. Cette page parcourt les commandes réellement tapées — pdflatex, xelatex, lualatex, latex suivi de dvipdfmx, ainsi que les routes CJK platex et uplatex — avec la poignée d’options qui méritent d’être retenues et la façon de lire la console quand un passage échoue.

Comment compiler un fichier .tex et ce que le passage laisse derrière lui

Une ligne suffit : pdflatex document.tex produit document.pdf. L’extension .tex est facultative et les options se placent toujours avant le nom du fichier. Ce qui revient n’est pourtant pas seulement le PDF. Deux autres fichiers apparaissent à côté : document.aux, un registre qui accumule les références croisées et les données de table des matières, et document.log, une transcription complète contenant tout ce qui a défilé à l’écran, et davantage. Ce sont des intermédiaires jetables — mais le premier décide de ce qui va suivre.

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

À cause de ce fichier .aux, une commande de compilation doit normalement être lancée deux fois. LaTeX lit un document une seule fois, du début à la fin : quand il compose la table des matières en page un, il ignore encore sur quelle page tombera la section 7. Le premier passage écrit dans .aux les numéros qu’il a découverts ; le second les relit et les insère dans le texte. Bibliographie et index allongent encore l’aller-retour. La manière dont LaTeX conclut que la boucle s’est stabilisée, et dont latexmk l’automatise, relève de la page consacrée aux compilations automatiques. Ici, il s’agit des commandes réellement invoquées à l’intérieur de cette boucle.

latex et pdflatex : toute la différence tient à un entier

latex produit du .dvi et pdflatex du .pdf, pourtant le binaire qui tourne dessous est le même fichier. Dans TeX Live 2024, les deux liens aboutissent à pdftex, et latex --version se présente sans détour comme pdfTeX 3.141592653-2.6-1.40.26 (TeX Live 2024). La différence ne se trouve pas dans le programme mais dans le fichier de format que chaque nom charge. pdflatex.ini inclut pdftexconfig.tex, où \pdfoutput = 1 est fixé. latex.ini inclut exactement le même fichier, puis l’écrase aussitôt avec \pdfoutput=0. Réduite à l’os, c’est cette seule valeur entière qui sépare les deux commandes.

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)

Comment un binaire unique sait-il alors quel format charger ? Il regarde le nom sous lequel il a été appelé. L’aide de pdfTeX le dit sans détour : il cherche NAME.fmt, où NAME est le nom d’invocation du programme. Renommez le lien et vous lancez un autre LaTeX. Pour contourner cette déduction, on passe -fmt=NAME ou -progname=NAME, ou l’on place une ligne %&format tout en haut du fichier source. C’est ce même mécanisme qui permet d’accrocher vingt noms distincts au seul exécutable pdftex.

\pdfoutput n’est pas seulement un réglage appliqué à la fabrication du format : c’est une primitive pdfTeX active à l’exécution. Placez \pdfoutput=0 tout en haut d’un fichier, avant \documentclass, et même un passage de pdflatex vous rendra un .dvi. En pratique, la ligne de commande est plus propre : -output-format=dvi ou -output-format=pdf, acceptées par pdfTeX comme par LuaTeX (seul XeTeX ne les connaît pas et emploie -no-pdf). LaTeX lui-même lit cette valeur et bascule en conséquence sa gestion des images : en mode DVI il charge l3backend-dvips.def, en mode PDF l3backend-pdftex.def. C’est précisément pour cela qu’une route accepte les figures .eps et l’autre les .pdf et .png.

pdflatex, xelatex ou lualatex : choisir selon les polices et Unicode

Un seul critère suffit. Si le document est en écriture latine et que la priorité va à la vitesse et à la compatibilité maximale des paquets, ce sera pdflatex. Dès qu’il s’agit de nommer une police déjà installée sur le système, ou de composer des caractères hors du domaine latin, on passe à xelatex ou lualatex. Les trois produisent du PDF et acceptent le même .tex ; seule diffère radicalement la porte par laquelle entrent les polices.

Pourquoi les commandes se sont-elles ainsi multipliées ? L’histoire l’explique en ligne droite. Knuth a commencé TeX en 1978, et son format de sortie était DVI — device-independent — parce que le PDF, présenté par Adobe en 1993, n’existait pas encore. pdfTeX est l’extension qui a comblé l’écart. Son auteur, Hàn Thế Thành, travaillait pour sa thèse sur la microtypographie : laisser les caractères déborder très légèrement de la marge droite et dilater les largeurs de glyphes de façon imperceptible pour égaliser le gris de la page. L’écriture directe du PDF, sans DVI intermédiaire, est issue du même travail. Si pdflatex est aujourd’hui le plus rapide et celui que la plupart des paquets présupposent, c’est simplement qu’il est en service depuis le plus longtemps.

xelatex lance XeTeX, développé par Jonathan Kew vers 2004. Avec le paquet fontspec, il suffit de nommer une police OpenType installée sur le système pour l’employer. XeTeX n’écrit toutefois pas le PDF directement : il produit un .xdv, forme étendue de DVI, qu’il confie à xdvipdfmx pour la conversion. -no-pdf arrête le passage au stade .xdv, et -output-driver=CMD remplace le convertisseur lui-même. Que XeTeX soit le seul des trois à ne pas connaître -output-format découle directement de cette architecture.

Il y a une surprise dans lualatex. Dans TeX Live 2024, le lien ne mène pas à luatex mais à luahbtex : LuaTeX doté de la bibliothèque de façonnage HarfBuzz, précisément ce qui permet de composer correctement les écritures aux règles de façonnage complexes, l’arabe et les écritures indiennes en tête. Le luatex nu existe toujours ; c’est lui que vise le dvilualatex évoqué plus bas. L’atout majeur de LuaTeX est dans son nom : un interpréteur Lua embarqué qui permet au document d’intervenir dans la coupure des lignes, le chargement des polices et d’autres rouages internes du compositeur. En alignant ici les numéros de version, on remarque une curiosité. tex --version affiche TeX 3.141592653 : Knuth numérote TeX en ajoutant une décimale de pi à chaque mise à jour, et pdfTeX comme XeTeX héritent tels quels de ce préfixe. Seul LuaTeX a quitté la tradition et s’annonce en Version 1.18.0.

CommandeBinaire (TeX Live 2024)SortiePolices et caractères
pdflatexpdftexPDFPolices TeX ; le plus rapide, compatibilité maximale
xelatexxetexPDF (via .xdv en interne)Polices OpenType du système via fontspec
lualatexluahbtexPDFPolices système + façonnage HarfBuzz + scripts Lua
latexpdftexDVIPolices TeX ; voie des figures EPS et de PSTricks
dvilualatexluatexDVIFonctions LuaTeX lorsque la sortie DVI est requise
platexeuptexDVIJaponais ; interne EUC, limité à JIS X 0208
uplatexeuptexDVIJaponais ; interne Unicode, caractères rares compris

latex puis dvipdfmx : pourquoi la route DVI survit

Deux raisons tiennent encore. D’abord, certaines mécaniques ne parlent que DVI : les paquets qui dessinent via PostScript, PSTricks en tête, donnent leur pleine mesure sur la route latex puis dvips. Ensuite, la composition japonaise, sujet de la section suivante, a traditionnellement emprunté ce chemin. latex document.tex écrit document.dvi, et dvipdfmx document.dvi en fait un PDF ; s’il faut du PostScript, c’est dvips qui s’en charge. Pour le souhait plus rare d’utiliser les fonctions de LuaTeX tout en obtenant du DVI, il existe dvilualatex, qui vise le luatex nu, sans HarfBuzz.

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

Commandes CJK : platex, uplatex et les solutions de rechange

Le japonais a ses propres commandes parce que sa composition a ses propres règles : écriture verticale, interdits kinsoku sur les caractères pouvant ouvrir ou clore une ligne, et espace fixe qui doit séparer texte japonais et texte latin. pTeX a inscrit ces règles dans le moteur lui-même plutôt que dans des macros, et LaTeX tournant par-dessus s’appelle pLaTeX, soit la commande platex. La première ligne du fichier de format platex.ini porte toujours « for pLaTeX (ASCII Nihongo LaTeX) », trace de son origine chez ASCII. upTeX, dû à Takuji Tanaka, étend pTeX pour que son code de caractères interne soit de l’Unicode complet ; LaTeX au-dessus est upLaTeX, la commande uplatex. Tous deux écrivent toujours du DVI et jamais du PDF directement.

La même surprise se répète ici. Dans TeX Live 2024, platex et uplatex sont tous deux des liens vers un binaire unique, euptex, où convergent aussi ptex, eptex et uptex. Ce qui les distingue est l’encodage interne des kanji. platex --version affiche e-upTeX 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.euc), tandis que uplatex --version se termine par (utf8.uptex). Autrement dit, un seul exécutable qui bascule -kanji-internal selon le nom d’appel. pLaTeX se comporte comme le pTeX classique à internes EUC, si bien que les caractères traités restent globalement dans JIS X 0208 ; upLaTeX est en Unicode en interne et laisse passer tels quels les kanji rares de noms propres et l’ensemble des idéogrammes unifiés CJK. Cette seule différence fait de uplatex le choix par défaut pour un nouveau document japonais. Ce regroupement est assez récent et précisément daté : le guide officiel de pTeX distribué avec TeX Live consigne que platex a tourné sur e-pTeX de TeX Live 2012 à 2022, puis est passé le 2023-06-01 à e-upTeX dans ce que le guide nomme le legacy-encoding-compatibility mode. Les primitives supplémentaires d’upTeX sont depuis accessibles à pLaTeX, tandis que le code interne des caractères japonais a été laissé volontairement hors Unicode pour préserver la compatibilité ascendante.

L’encodage interne et celui du fichier d’entrée sont deux choses distinctes. L’entrée se règle avec -kanji=STRING, qui accepte euc, jis, sjis, utf8 ou uptex. Les TeX Live récents utilisent UTF-8 par défaut, on peut donc souvent l’omettre — mais l’indiquer explicitement garde la compilation stable quand l’environnement change. Pour faire passer de l’UTF-8 sans BOM de façon fiable, on ajoute -no-guess-input-enc, qui coupe entièrement la détection d’encodage. La sortie est du DVI : dvipdfmx termine le travail.

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

Le chinois et le coréen n’empruntent pas du tout cette route. On les confie normalement à un moteur nativement Unicode : pour le chinois, xelatex ou lualatex avec l’ensemble ctex (qui appelle xeCJK et consorts en dessous) ; pour le coréen, les mêmes moteurs avec kotex. Le japonais offre la même possibilité : en chargeant luatexja sous lualatex, le PDF sort directement. Sur cette voie, -kanji devient inutile : un moteur entièrement bâti sur Unicode n’a plus d’encodage interne à basculer.

Les options qui valent la peine : -interaction=nonstopmode, -halt-on-error, -output-directory

Les options précèdent toujours le nom du fichier, et celles qui suivent fonctionnent avec n’importe laquelle des commandes pdfTeX, XeTeX et LuaTeX. Quatre d’entre elles justifient leur place au quotidien : -synctex=1 pour l’intégration à l’éditeur, -interaction=nonstopmode pour qu’un passage ne reste pas bloqué, -halt-on-error pour au contraire abandonner au premier problème, et -file-line-error pour mettre le message sous une forme analysable par une machine.

OptionEffet
-synctex=1Écrit document.synctex.gz et permet les sauts entre éditeur et PDF
-interaction=nonstopmodeVa jusqu’au bout au lieu d’attendre une saisie sur erreur ; batchmode coupe en plus la sortie du terminal
-halt-on-errorAbandonne à la toute première erreur ; aucun PDF n’est produit
-file-line-errorRéécrit l’en-tête du message en ./document.tex:3:, analysable par les IDE et la CI
-output-directory=DIRÉcrit la sortie et les fichiers auxiliaires dans DIR ; DIR doit exister au préalable
-jobname=NAMEFixe le nom de base, avant l’extension, de tous les fichiers de sortie
-draftmodeS’exécute sans écrire le PDF (pdfTeX / LuaTeX) ; utile pour les passages intermédiaires qui ne font que fixer les références
-output-format=FORMATChoisit dvi ou pdf (pdfTeX et LuaTeX seulement ; XeTeX emploie -no-pdf)
-shell-escapeLève toute restriction sur l’exécution de commandes externes via \write18 (lire l’avertissement ci-dessous)
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 cache un piège dans lequel les chaînes d’intégration continue tombent sans arrêt : le répertoire indiqué doit déjà exister. L’aide de pdfTeX le dit elle-même : elle utilise un DIR existant. S’il manque, le passage annonce « Please type another transcript file name », puis se termine par ! Emergency stop et « Fatal error occurred, no output PDF file produced! ». Comme la cause n’a rien à voir avec la composition, même un lecteur aguerri des journaux LaTeX y perd un instant. Un mkdir -p à la ligne précédente règle tout.

-shell-escape : pourquoi minted en a besoin et pourquoi c’est dangereux

Cette option accorde au document le droit d’exécuter des commandes shell arbitraires sur votre machine. Les commandes externes ne sont pourtant pas entièrement fermées par défaut. TeX Live tourne en mode restreint et chaque passage affiche la ligne restricted \write18 enabled.. Dans cet état, \write18 ne peut appeler que les programmes figurant sur une liste d’autorisation dans texmf.cnf, et dans TeX Live 2024 cette liste est courte : bibtex, bibtex8, extractbb, gregorio, kpsewhich, makeindex, memoize-extract.pl, memoize-extract.py, repstopdf, r-mpost, texosquery-jre8. Si la bibliographie et l’index fonctionnent sans la moindre option, c’est précisément que ces deux entrées sont autorisées d’emblée.

pygmentize ne figure pas sur cette liste. texmf.cnf l’en écarte délibérément, avec un commentaire mettant en doute la sûreté de sa fonction de filtre. minted, qui colorise les listings de code, appelle précisément ce programme : il ne fonctionne donc pas en mode restreint et seul un -shell-escape complet convient. Et complet veut dire complet : un .tex reçu d’autrui peut, en une seule compilation, effacer des fichiers, expédier des données locales ou installer quelque chose. La règle peut rester simple — ne l’activer que pour des documents que l’on a écrits soi-même, dans un répertoire que l’on maîtrise. Jamais pour un modèle téléchargé ni pour une soumission arrivée en relecture.

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

Lire la sortie console quand une compilation échoue

On lit à partir de la première ligne commençant par !, et non depuis la fin. Les erreurs LaTeX se propagent : ce qui reste à l’écran en dernier est généralement un dommage collatéral causé par la première, dont la cause se trouve plus haut. Tout rapport d’erreur a la même forme : la ligne ! nomme le symptôme, et la ligne suivante commençant par l. indique l’endroit.

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

La ligne qui compte est l.3. Elle désigne la ligne 3 du source, mais elle s’affiche coupée en deux exactement là où TeX s’était arrêté de lire. Tout ce qui précède la coupure a été consommé ; tout ce qui suit ne l’a pas encore été. Ici, la coupure tombe juste après x^, ce qui désigne d’emblée le caractère d’exposant comme coupable. ! Undefined control sequence. suit le même schéma, et la commande mal orthographiée placée juste avant la coupure constitue déjà la réponse. Le ? final est une invite : le passage s’est arrêté dans le errorstopmode par défaut et attend. Entrée poursuit, x abandonne.

Ce dialogue est précisément ce dont scripts et CI ne veulent pas, d’où les modes d’interaction. -interaction=nonstopmode affiche tout sans s’arrêter, batchmode coupe en plus la sortie du terminal, et scrollmode ne pose de question que lorsqu’un fichier reste introuvable. Si l’on préfère ne voir que le premier problème, -halt-on-error clôt le passage sur ! Emergency stop. et « Fatal error occurred, no output PDF file produced! ». Ajouter -file-line-error réécrit l’en-tête en ./document.tex:3: Missing $ inserted., que les éditeurs et la CI transforment en lien cliquable. Quel que soit le choix, la transcription complète atterrit toujours dans .log : si elle échappe au terminal, le même texte attend dans le fichier.

Quelle commande de compilation choisir

  • Un document en écriture latinepdflatex. Le plus rapide, et la valeur par défaut que la plupart des paquets présupposent.
  • Nommer une police du système d’exploitationxelatex ou lualatex ; tous deux passent par fontspec.
  • Écritures à façonnage complexe, ou scripter le compositeur lui-mêmelualatex (en réalité luahbtex, HarfBuzz compris).
  • Un nouveau document japonaisuplatex puis dvipdfmx, ou lualatex avec luatexja.
  • Chinois ou coréenxelatex ou lualatex avec ctex ou kotex ; aucune étape DVI.
  • PSTricks et autres mécaniques exclusivement DVIlatex puis dvips ou dvipdfmx.

Une dernière habitude de diagnostic. Quand le bouton de compilation de l’éditeur échoue, tapez d’abord la même commande à la main dans un terminal. Si elle passe, le problème vient de la configuration de l’éditeur et non du document. Avant de transmettre un fichier ou de le confier à la CI, un passage avec -halt-on-error -file-line-error -interaction=nonstopmode rend lisible la position de la première vraie erreur. Au quotidien, presque personne ne tape ces commandes deux fois à la main : le travail revient à latexmk, qui compte les passages et appelle dvipdfmx à votre place. La façon dont il sait quand s’arrêter fait l’objet de la page consacrée aux compilations automatiques.