• [^] # Re: Mais non, il ne faut pas un makefile pour gérer du latex !

    Posté par . En réponse à la dépêche Préparation de documents LaTeX avec BSD Owl. Évalué à 4.

    Sommaire

    Tu sais, que tu peut défendre l'idée que latexmk est mieux sans dire que le reste c'est de la merde ?

    Je me permets de te faire remarquer que je n'ai jamais écrit ça. Tu ne fais peut être pas la différence « truc ne marche pas » et « truc est de la merde », moi si. Mais passons.

    Qu'est que fonctionner dans le contexte ?

    Je reprends donc depuis le début. Ma compréhension de la dépêche est que l'auteur propose un outil qui aurait deux fonctions. La première est d'assurer la production d'un pdf/ps à partir (notamment) d'un fichier latex maître et de toutes ses dépendances. La deuxième est de faciliter l'interaction avec des personnes qui n'utilisent pas un gestionnaire de version (ou pas le même que l'auteur) grâce à un mécanisme d'horodatage des fichiers compilés qui permettrait de retrouver les sources utilisées pour produire la version partagée. J'affirme que la solution proposée ne fonctionne pas dans des cas classiques et ne lutte pas contre les erreurs humaines classiques (notamment en tournant le dos aux bonnes pratiques en développement logiciel). Mes arguments sont simples et classiques pour quelqu'un qui connaît bien latex. Ce n'est probablement pas le cas de l'auteur qui me présente ensuite comme arrogant quand je lui dis. (mais bon, on s'en fout, l'important c'est que ça ne fonctionne pas).

    Je vais d'abord parler de la production automatique du document pdf (pour simplifier, je dirai juste pdf, mais ça pourrait être ps, voire d'autres choses). Mais pour ça, je dois préciser ce que je veux dire par production automatique d'un pdf. Mon point de vue est que je dois pouvoir taper quelque chose comme make toto.pdf et obtenir totalement automatiquement le bon fichier toto.pdf à la fin de l'exécution de la commande. J'insiste sur le fait que ça doit être automatique à chaque fois, quelles que soient mes modifications sur l'ensemble des sources. Et j'insiste sur le fait que ça doit être le bon fichier, pas un machin qui ne tiendrait pas compte de certaines de mes modifications. Et je veux en plus que ça soit fait de façon optimale en temps de calcul. Car latex reste lent : je pense qu'on tourne autour de 50 pages à la seconde sur un PC classique. Si on doit faire 3 ou 4 passes sur une thèse de 200 pages, ça fait 15 secondes, c'est quand même chiant pour juger les effets de la modification d'un paramètre de présentation, par exemple. Et c'est sans packages évolués comme tikz et ses amis avec lesquels on peut descendre à beaucoup moins que 50 pages par seconde.

    Si j'insiste sur ces trois aspects, automaticité, correction et efficacité, c'est que je sais par expérience (plus de 20 ans de latex) qu'un compromis engendre des problèmes. Si le processus n'est pas correct, on peut être amené à diffuser un document incomplet ou incohérent. Si le processus est lent (trop de passes), on va contourner la lenteur en réduisant artificiellement le nombre de passes, ce qui rendra le document incorrect (c'est ce que préconise explicitement l'auteur, ce qui un très mauvais choix dont je constate les effets délétères très régulièrement dans mon travail d'édition scientifique). Enfin, si ce n'est pas automatique, on oubliera un jour d'ajouter des dépendances ou d'en enlever, entraînant des problèmes de correction et/ou d'efficacité (trop de compilation ou pas assez). Si les systèmes de production actuels sont si complexes c'est notamment par ce qu'ils visent exactement ces trois aspects avec en plus la reproductibilité.

    Pas d'automaticité

    Or, la solution proposée n'est pas automatique : en particulier, elle ne gère pas automatiquement les dépendances. L'auteur repousse ça au futur alors que des solutions existent aujourd'hui (comme latexmk ou d'autres comme arara ou Rubber). Au delà du problème classique évident que ça pose dans tout contexte de dépendances entre objets, il y a des cas un peu spécifiques à latex. Prenons un fichier maître comme suit monlatex.tex :

    \documentclass{article}
    \begin{document}
    \include{bla1}
    \include{bla2}
    \end{document}

    et deux fichiers inclus bla1.tex :

    \section{Bla 1}
    Mon bla 1.

    et bla2.tex :

    \section{Bla 2}
    Mon bla 2.

    Avec une gestion de dépendances (automatique ou non), monlatex.pdf dépend évidemment de monlatex.tex, bla1.tex et bla2.tex. Maintenant, imaginons que les deux parties soient volumineuses et donc longues à compiler. Il est classique dans cette situation d'utiliser la commande latex \includeonly qui permet de restreindre la compilation en n'incluant que les parties qu'on souhaite (c'est un peu plus subtil que cela, mais peu importe). J'ajoute par exemple avant le \begin{document} l'instruction \includeonly{bla1} et je recompile (avec latexmk, bien sûr). Comme la mise à jour des dépendances est automatique, celle à bla2.tex est supprimée et aucune modification du fichier ne produit de mise à jour de monlatex.pdf. Au contraire, dès que j'enlève l'appel à \includeonly, la dépendance revient, ce qui est exactement ce qu'on veut. En particulier (et c'est la subtilité au dessus), les labels et autres objets du même type définis par bla2.tex qui étaient conservés et utilisés lors de la compilation réduite à l'inclusion de bla1.tex sont mis à jour automatiquement (donc avec le bon nombre de passes) si besoin est (notamment si bla2.tex a été modifié). Impossible d'avoir ce type de comportement avec la solution proposée.

    Optimalité ou correction, il faut choisir

    Passons maintenant à l'optimalité. Il faut savoir qu'en latex le nombre de passes nécessaires à l'obtention d'un document correct n'est pas borné à priori. Il existe en fait des documents qui ne sont pas compilables de façon stable. Par exemple (issu de stackexchange) :

    \documentclass{article}
    \pagenumbering{Roman}
    \begin{document}
    a\clearpage b\clearpage c\clearpage
    \begin{figure}[!t]
    \framebox(200,430){}
    \caption{a figure to take up space}
    \end{figure}
    Some interesting text about something in Section \ref{x},
    which starts on page \pageref{x}.
    \section{zzz\label{x}}
    The text of an interesting section.
    \end{document}

    Au delà des cas pathologiques, il faut bien comprendre qu'il est impossible de savoir combien de passes seront nécessaires à obtenir un document correct en se basant seulement sur la liste des fichiers modifiés dans l'ensemble des dépendances. En effet, la nature des modifications induit des besoins différents au niveau des passes et des outils. Prenons un exemple simple. Je modifie monlatex.tex en

    \documentclass{article}
    \begin{document}
    \include{bla1}
    \include{bla2}
    \bibliographystyle{plain}
    \bibliography{mabib.bib}
    \end{document}

    et j'ajoute donc un fichier bibtex (tient une nouvelle dépendance à ajouter à la main... ou pas avec latexmk) :

    @Book{RobertBozo2014,
     author = {Bozo, Robert},
     title = {Oui Oui fait du latex},
     publisher = {Bozo Inc.},
     year = 2014}
    

    Quand je lance latexmk, j'obtiens les passes suivantes :
    1) pdflatex monlatex.tex : détection de la nouvelle dépendance mabib.bib ;
    2) bibtex monlatex : bug car pas de citation, mais latexmk s'en fout, il connaît cette erreur et sait que ce n'est pas un vrai problème. Il découvre quand même le fichier monlatex.bbl (vide ou presque) qui devient une nouvelle dépendance (on sait jamais, je pourrai vouloir le modifier à la main) ;
    3) pdlfatex monlatex.tex : normal car le bbl a été produit et il faut l'intégrer.

    Que se passe-t-il maintenant si je modifie bla1.tex ? Tout dépend de la nature de la modification, chose que le système proposé par l'auteur ne peut pas détecter. Si mon nouveau bla1.tex est le suivant

    \section{Bla 1}
    Mon bla 1 modifié.

    alors une seule passe de pdflatex est suffisante (et c'est ce que fait latexmk, bien sûr). En revanche, si mon nouveau bla1.tex est

    \section{Bla 1}
    Mon bla 1 \cite{RobertBozo2014}.

    alors il faut trois passes : un pdflatex, un bibtex et un pdflatex.

    Et tout ça n'est qu'un exemple de base absolument standard (comme je le disais plus haut). Dès qu'on commence à utiliser des packages évolués, la situation se complique. On peut voir sur stackexchange des exemples de documents qui nécessitent n passes pour n arbitraire. C'est le cas par exemple de documents produits avec longtable.

    La solution proposée par l'auteur est de choisir à la main le nombre de passes. On peut donc choisir entre quelque chose d'inefficace (sachant que pdflatex+bibtex+pdflatex est en gros le minimum pour un document avec des citations, mais ça peut encore être incorrect s'il y a des modifications de la table des matières) ou quelque chose d'incorrect (pas assez de passes dans certains cas). Comme je l'ai dit en introduction, c'est inacceptable, d'autant qu'il existe des solutions qui fonctionnent parfaitement.

    En outre, l'auteur ne sait pas (apparemment) que les documents latex sont très dynamiques. Si j'utilise un style de citation qui inclut les noms d'auteurs dans les étiquettes, une modification du fichier bibtex peut entraîner plusieurs recompilations du latex car les étiquettes peuvent changer et donc entraîner des modifications de mise en page. L'exemple de mon cv donné plus haut montre aussi que certains compteurs peuvent être calculés par biber (le remplaçant de bibtex) en fonction du contenu des fichiers bibtex mais aussi en fonction des commandes dans le latex (en gros, biblatex permet la définition de collections dont la taille peut notamment être utilisée dans le latex lui même). Tout ça conduit à des compilations plus ou moins complexes.

    Bref, tout ça est connu et archiconnu et c'est pour ça qu'il existe pléthore d'outils de compilation spécifique à latex. On peut voir ça (à juste titre) comme une limitation de latex, mais ça ne change au rien au fait qu'il faut la gérer, ce qu'un système à la make ne peut pas faire simplement.

    L'horodatage est une mauvaise idée

    Terminons par cette idée d'horodatage. Le cas d'utilisation (partage de documents en dehors d'un gestionnaire de version) est tout à fait réaliste, mais la solution proposée est naïve (c'est globalement le cas de toute la dépêche, d'ailleurs). Elle repose sur la confusion entre instant de compilation et instant de production. Dois-je vraiment expliquer cela ? Si je compile mon latex maintenant et que j'obtiens monlatex-2014年11月01日-15-16.pdf, est-ce que ça veut dire que c'est la version des sources du 1er novembre 2015 à 15h16 ? Bien sûr que non ! C'est le moment de la compilation, nom de dieu ! Et quand bien même je compilerais juste après avoir écrit quelque chose, rien ne garantit dans cette solution que je pourrai revenir à la version du 1er novembre 2015 à 15h16 car je ne sais pas si cette version existe dans mon gestionnaire de versions !

    Et donc, il ne faut pas faire comme ça. C'est tellement évident d'après toute l'histoire du développement logiciel qu'on se demande comment on peut avoir une telle idée (oui je sais je suis arrogant, c'est ça...). D'autant qu'il existe des solutions simples. D'abord, il faut intégrer dans le pdf lui-même de quoi retrouver la version des sources utilisée pour le produire dans le gestionnaire de version. C'est facile avec gitinfo2 et il y a d'autres packages pour d'autres gestionnaires de version. Ensuite, il faut prévoir un mode de release dans le makefile (ou sous forme d'un hook git, par exemple) qui ne fonctionne que sur une version vraiment existante dans le gestionnaire de version (donc qui refuse de produire le pdf s'il y a des modifications non commitées) et qui utilise dans le nom de fichier la date (et heure) de la version concernée. Encore une fois, ça ne pose pas de problème particulier. Notons que gitinfo2 ne donnera que des informations sur une version existante des sources et n'utilisera donc pas la date de la compilation mais bien celle de la version.

    Conclusion : ça ne marche pas bien

    Voilà, soyons finalement gentil avec l'auteur, sa solution ne marche pas bien. Elle boite pas mal. Il existe des solutions qui marchent très bien, elles. Elles existent depuis longtemps. Les personnes arrogantes comme moi le savent. Les personnes arrogantes comme l'auteur pensent probablement qu'elles n'ont pas besoin de regarder ce qui se fait pour compiler du latex et qu'elles sont suffisamment compétentes pour faire ça elles-mêmes. Chacun son arrogance.