Travailler avec de gros documents

Personne n’écrit une thèse de 300 pages dans un seul fichier .tex. La réponse de LaTeX à un document volumineux tient en trois commandes — \input, \include et \includeonly — qui découpent le projet en un fichier par chapitre, puis permettent de ne recomposer que le chapitre en cours. Le plus astucieux est la mécanique sous-jacente : chaque fois qu’un chapitre inclus se termine, LaTeX inscrit un point de contrôle dans son fichier .aux et y consigne la valeur de tous les compteurs, numéro de page compris. C’est pourquoi un chapitre sauté ne dérègle pas la numérotation des suivants. Cette page part de l’organisation des dossiers, traverse le piège des chemins relatifs où presque tout le monde tombe une fois, et se termine par les pannes que seule une compilation complète révèle.

Comment organiser un gros projet LaTeX

Tout part d’une règle : le fichier principal ne contient aucun texte. main.tex comporte la classe de document, le préambule et une liste de lignes \include, rien d’autre. Les chapitres vivent dans chapters/, les images dans figures/, la base bibliographique dans bib/. Le fichier principal se lit alors comme une table des matières, et réordonner des chapitres revient à réordonner des lignes. C’est cette même propriété qui rend la coécriture supportable : chacun touche des fichiers distincts, les conflits se raréfient et un diff Git reste dans le seul chapitre modifié. Dès que le préambule grossit, on le déplace dans preamble.tex et on le charge par \input{preamble} — jamais par \include, pour une raison que la section suivante éclaire.

text
thesis/
  main.tex
  preamble.tex          % packages and settings
  chapters/01-intro.tex  02-method.tex  03-results.tex
  figures/              % all images, next to main.tex
  bib/refs.bib
latex
% main.tex -- no prose here, just structure
\documentclass[11pt,a4paper]{report}
\input{preamble}

\begin{document}
\tableofcontents

\include{chapters/01-intro}
\include{chapters/02-method}
\include{chapters/03-results}

\bibliographystyle{plain}
\bibliography{bib/refs}
\end{document}

Numéroter les fichiers — 01-intro.tex, 02-method.tex — aligne la liste de l’éditeur sur l’ordre de lecture. L’autre ligne qui vaut la peine est % !TEX root = ../main.tex en tête de chaque fichier de chapitre. TeXShop, TeXstudio, VS Code et la plupart des éditeurs la lisent et compilent main.tex même lorsqu’un chapitre est au premier plan. Sans elle, on finit toujours par compiler un chapitre seul et par rencontrer ! LaTeX Error: Missing \begin{document}. — conséquence inévitable d’un fichier dépourvu de \documentclass, qui coûte pourtant quelques minutes de perplexité.

La différence entre \input et \include

\input{f} colle le contenu de f.tex à cet endroit, et rien de plus. \include{f} opère au niveau du chapitre : il émet un \clearpage avant et après et — c’est là l’essentiel — il ouvre un fichier f.aux distinct vers lequel il redirige les informations auxiliaires. Ce .aux par chapitre est toute la raison d’être de \include. Numéros de page, étiquettes de références croisées et lignes de table des matières sont rangés chapitre par chapitre ; lorsqu’un chapitre est ensuite sauté, ce sont précisément ses données que l’on relit de la compilation précédente. \input, lui, ne laisse aucune trace de frontière de fichier, ce qui en fait l’outil de tout ce qui est plus petit qu’un chapitre : chargement du préambule, macros communes, corps d’un tableau, formules répétées.

CommandeEffetSaut de pageImbrication
\inputdéveloppe le contenu d’un fichier .tex sur placeaucunoui
\includeintègre un chapitre doté de son propre .aux\clearpage avant et aprèsnon
\includeonlypréambule uniquement ; limite les \include traités
\subfilede subfiles ; la partie se compile aussi seuleaucunoui
\subimportde import ; les chemins relatifs partent de ce dossieraucunoui

La colonne de droite abrite la différence la plus coûteuse. Écrire un \include dans un fichier lui-même inclus arrête la compilation sur ! LaTeX Error: \include cannot be nested. La restriction paraît arbitraire, mais l’implémentation la rend inévitable : le noyau ne réserve qu’un seul flux de sortie pour le .aux d’un chapitre, si bien qu’un \include interne n’aurait nulle part où écrire le sien. Pour découper un chapitre en sections, on les appelle depuis le fichier du chapitre avec \input{chapters/02-method/setup}. Autre conséquence : \include n’a pas non plus sa place dans le préambule, où il produit l’avertissement \include should only be used after \begin{document}. C’est précisément pour cela qu’un préambule se charge avec \input.

Une autre asymétrie coûte cher en silence. \input{chapters/ch9} sur un fichier inexistant s’arrête sur ! LaTeX Error: File ... not found., alors que \include{chapters/ch9} dans la même situation se contente d’écrire No file chapters/ch9.tex. dans le journal et compile comme si de rien n’était. Une faute de frappe dans un \include ne produit donc pas une erreur mais un PDF auquel manque un chapitre entier. Après avoir renommé un chapitre, prendre l’habitude de chercher No file dans le journal.

Compiler un seul chapitre avec \includeonly, et pourquoi la pagination reste juste

Placer \includeonly{chapters/02-method} dans le préambule ne traite que ce \include et saute les autres. Une compilation complète de plusieurs minutes s’achève en quelques secondes — et la pagination comme les références croisées des chapitres sautés restent justes. Le procédé comporte deux volets. D’abord, même pour un chapitre sauté, LaTeX écrit dans main.aux la ligne \@input{chapters/01-intro.aux} : le .aux de la compilation précédente est donc toujours relu, et les entrées \newlabel qu’il contient maintiennent \ref opérationnel. Ensuite, à la fin de chaque chapitre, LaTeX ajoute à son .aux la valeur courante de tous les compteurs. Les sources du noyau appellent cet enregistrement, mot pour mot, un point de contrôle ; sauter un chapitre revient simplement à le rejouer, ce qui porte les compteurs de page, de chapitre et de figure exactement là où ce chapitre s’était arrêté.

latex
% in the preamble of main.tex
\includeonly{chapters/02-method}
% several at once, comma separated, no spaces needed around the commas
% \includeonly{chapters/02-method,chapters/03-results}
text
% chapters/01-intro.aux, written by the last full build (trimmed)
\newlabel{ch:intro}{{1}{2}{}{}{}}
\@setckpt{chapters/01-intro}{
\setcounter{page}{5}
\setcounter{chapter}{1}
\setcounter{figure}{0}
}

Grâce à ces deux volets, le PDF d’une compilation partielle ressemble plus au résultat final qu’on ne l’imagine. La table des matières elle-même tient bon : le .toc est écrit en fin de compilation à partir des fichiers .aux, si bien qu’un chapitre sauté y figure encore avec son numéro de page de la fois précédente. Une condition demeure toutefois : faire d’abord une compilation complète. Sauter un chapitre dont le .aux n’existe pas encore laisse ses références à ?? et inscrit LaTeX Warning: There were undefined references. dans le journal. Deux détails méritent d’être connus : \include et \includeonly retirent un .tex final avant de comparer les noms, donc \includeonly{chapters/02-method.tex} correspond aussi ; et \includeonly appartient au seul préambule — placé après \begin{document}, il donne ! LaTeX Error: Can be used only in preamble. Avant de rendre le travail, on supprime la ligne et on recompile tous les chapitres. Le PDF d’une compilation partielle est une approximation de travail, pas le document achevé.

Pourquoi les chemins relatifs partent du fichier principal, pas du chapitre

Ni \input ni \include ne change le répertoire courant. TeX résout chaque chemin relatif par rapport au répertoire de travail de la compilation, c’est-à-dire normalement là où se trouve main.tex. Un chemin d’image écrit dans chapters/02-method.tex doit donc s’écrire tel qu’on le voit depuis main.tex. \includegraphics{figures/plot} fonctionne ; \includegraphics{../figures/plot}, pourtant correct vu du dossier du chapitre, échoue sur ! LaTeX Error: File ... not found. C’est là qu’on en conclut qu’avoir déplacé un chapitre a cassé ses figures. Seul le fichier a bougé ; le point de référence, lui, est resté main.tex.

Deux remèdes existent. Le plus courant est \graphicspath, fourni par graphicx, qui enregistre les dossiers à explorer. Sa syntaxe est singulière et mérite d’être retenue : chaque dossier reçoit sa propre paire d’accolades et doit se terminer par une barre oblique\graphicspath{{figures/}{chapters/figures/}}. Dès lors, n’importe quel chapitre peut écrire \includegraphics{plot}, sans dossier ni extension. Le séparateur reste la barre oblique, y compris sous Windows. Le second remède convient aux projets où chaque chapitre possède ses propres figures : \subimport{chapters/}{02-method}, du package import, fait résoudre les chemins relatifs de ce chapitre à partir de chapters/. Si le chapitre doit un jour rejoindre un autre projet, cette disposition se transporte mieux.

latex
% option A -- one shared figure folder, registered once in the preamble
\usepackage{graphicx}
\graphicspath{{figures/}{chapters/figures/}}   % braces per folder, trailing slash
% then, anywhere in any chapter:
%   \includegraphics[width=0.8\linewidth]{plot}

% option B -- each chapter carries its own figures
\usepackage{import}
% in main.tex, instead of \include{chapters/02-method}:
\subimport{chapters/}{02-method}   % paths inside resolve from chapters/

Composer un chapitre seul : subfiles et standalone

\includeonly sert à composer vite un chapitre au sein de l’ensemble, pas à en faire un PDF indépendant. Pour que le chapitre soit lui-même un document, on emploie le package subfiles. Avec \documentclass[../main]{subfiles} en tête du fichier de chapitre, celui-ci se compile seul en empruntant le préambule principal, tandis que le fichier principal continue de l’insérer par \subfile{chapters/02-method}. Les figures disposent du même principe : une image TikZ écrite pour la classe standalone se compose seule en un PDF d’une page, et le document principal l’intègre avec \usepackage{standalone} et un simple \input.

latex
% main.tex
\documentclass{report}
\usepackage{graphicx}
\usepackage{subfiles}
\begin{document}
\subfile{chapters/02-method}
\end{document}

% chapters/02-method.tex -- also compiles on its own
\documentclass[../main]{subfiles}
\begin{document}
\chapter{Method}
This chapter builds alone and inside the book.
\end{document}

Le prix à payer est tout aussi net. Un chapitre compilé seul commence à la page 1 et ne voit pas les \label définis ailleurs : \ref donne ?? et le journal signale LaTeX Warning: There were undefined references. Le choix suit l’usage : \includeonly pour aller vite tout en conservant la numérotation d’ensemble, subfiles pour remettre « le chapitre 3 » à son encadrant sous forme de fichier. Une thèse rendue en un seul PDF se contente très bien de \include et \includeonly ; un projet dont les chapitres vivent aussi comme articles, notes de cours ou polycopiés préfère subfiles. Mêler les deux dans un même projet revient à entretenir deux fois le préambule, ce qui est rarement rentable.

Des compilations d’essai plus rapides avec l’option draft

\documentclass[draft]{report} remplit deux offices lors des essais sur un gros document. D’abord, il signale par une règle noire en marge toute ligne qui déborde du bloc de texte — une overfull hbox —, ce qui rend les mauvaises coupures visibles d’un coup d’œil. Ensuite, il cesse de rendre les images et les remplace par un cadre portant le nom du fichier ; le traitement des images étant évité, la compilation s’allège nettement, d’autant plus que le chapitre contient de figures. Pour n’agir que sur les images, on restreint avec \usepackage[draft]{graphicx}. À l’inverse, \overfullrule=5pt ne produit que les règles et laisse les images visibles. Pour la compilation définitive, draft redevient final.

latex
\documentclass[draft]{report}   % skip images, show overfull rules
% scope it to images only:
% \usepackage[draft]{graphicx}
% keep images, still flag overfull lines:
% \overfullrule=5pt

Quand un chapitre passe seul mais pas le document entier

La cause tient presque toujours en quatre cas. (1) Le chapitre emploie un package ou une macro qui n’existe que dans son propre préambule : seul il passe, dans le livre survient ! Undefined control sequence. (2) Deux chapitres définissent le même \label, d’où LaTeX Warning: Label ... multiply defined. et une référence qui pointe discrètement au mauvais endroit. (3) Un chemin relatif écrit depuis le dossier du chapitre, le piège de la section précédente. (4) Un .aux périmé. Le cas (2) est le plus dangereux, car il n’échoue pas : il imprime un mauvais numéro. Préfixer les étiquettes par le chapitre, comme \label{fig:method-setup}, l’élimine structurellement.

Il vaut la peine de savoir comment un .aux se corrompt. Une compilation interrompue, ou un chapitre renommé, peut laisser un .aux à moitié écrit. La compilation suivante le relit et échoue sur une ligne sans rapport avec la dernière modification. Dès qu’une erreur surgit là où l’on n’a rien touché, on supprime d’abord les fichiers engendrés. À la main : .aux, .toc, .lof, .lot et .out — sans oublier que les .aux de chapitre se trouvent aussi dans chapters/. Avec latexmk, latexmk -c efface les fichiers intermédiaires et latexmk -C efface en plus la sortie. Après suppression, compiler deux fois pour que références et table des matières se stabilisent.

  • Avant une session sous \includeonly, faire une compilation complète pour que chaque chapitre dispose d’un .aux récent.
  • Externaliser les figures TikZ lourdes, ou les pré-rendre en PDF et les charger par \includegraphics.
  • Placer % !TEX root = ../main.tex en tête de chaque fichier de chapitre pour que le document principal soit toujours compilé.
  • Sans le package import, garder figures/ et bib/ à côté de main.tex, pas à côté des chapitres.
  • Préfixer les étiquettes par le chapitre, comme fig:method-setup, pour rendre multiply defined structurellement impossible.
  • Avant de rendre, retirer \includeonly et draft, supprimer les fichiers engendrés, compiler proprement et lire le journal jusqu’au bout en cherchant Warning et No file.

Un dernier mot sur le rythme. Les longs documents réussissent non pas à ceux qui compilent toujours tout, ni à ceux qui ne compilent jamais qu’un fragment, mais à ceux qui alternent. Au quotidien, on travaille le chapitre en cours sous \includeonly et l’on confie la recompilation à l’enregistrement à latexmk. Aux jalons, on retire \includeonly et draft, on compile l’ensemble et l’on regarde numérotation, table des matières, index et bibliographie se mettre en place. Avant de rendre, on supprime les fichiers engendrés, on compile proprement et on lit le journal jusqu’au bout. Le découpage a l’air d’une astuce de vitesse ; c’est tout autant une astuce de sérénité, puisqu’il rend bon marché, n’importe quel jour, la recomposition correcte de l’ensemble.