Du Lisp

 x0r   0
lisp

Je programme depuis l’âge de sept ans et au cours de ma vie, j’ai eu l’occasion et la curiosité d’essayer et d’utiliser de nombreux langages de programmation. Mais parmi les langages que je connais, le Lisp est celui qui a de loin le plus bousculé ma vision de la discipline.

J’ai découvert le Lisp de manière complètement fortuite il y a deux ans. Je cherchais en fait un outil de mind-mapping et j’étais alors tombé sur Org mode couplé à Spacemacs, lui-même une surcouche pour GNU Emacs.

De fil en aiguille, Emacs m’a fait découvrir Emacs Lisp. À partir de là, j’ai fini par adopter Common Lisp et dans une moindre mesure Clojure, en essayant au passage Haskell (qui n’est certes pas un Lisp, mais semble faire partie de la famille en tant que membre d’honneur). Mais ma dernière découverte, et de loin la plus étonnante, est le langage Racket, que j’étudie actuellement.

Au cours de ces différents essais de langages, ma bien-aimée a essayé et adopté Common Lisp plutôt que le C pour une idée de jeu qu’elle avait depuis plus de dix ans et j’ai aussi fait des prototypes de générateurs de texte à base de chaînes de Markov et un solveur de picross.

La famille Lisp

Le Lisp d’origine date de la fin des années 1950, ce qui fait de la famille des Lisp une des plus anciennes qui existent.

Il est difficile d’illustrer ce qui m’attire dans les Lisp sans donner au moins un exemple de code. En voici un, exprimé en Common Lisp, qui calcule la factorielle d’un nombre n en utilisant une fonction auxiliaire f et une récursion terminale :

(defun factorial (n)
  "Calcule la factorielle du nombre N."
  (flet ((f (acc n)
           (if (<= n 1)
               acc
               (f (* acc n) (1- n)))))
    (f 1 n)))

Je déclare ici une fonction factorial, acceptant un seul paramètre nommé n, accompagné d’une petite description destinée à un système de génération documentaire. J’y introduis une fonction auxiliaire f prenant en paramètre un résultat pratiel acc (pour « accumulateur ») et le nombre dont on calcule la factorielle, toujours appelée n.

Dans cette fonction auxiliaire, si n est inférieur ou égal à 1, le calcul est terminé et on renvoie acc. Sinon, on appelle f récursivement. Avec cette fonction auxiliaire définie, il ne reste plus qu’à l’appeler avec 1 et n comme paramètres pour calculer le résultat.

Ce qui saute immédiatement aux yeux sont la quantité de parenthèses. Il s’agit en fait de la représentation canonique de listes, qui sont délimitées par des parenthèses et dont chaque élément est séparé par un blanc. On dit aussi que ces listes sont représentées sous la forme de S-expressions.

Ainsi, (f (* acc n) (1- n)) est une liste dont les éléments sont, dans l’ordre, le symbole f, la liste (* acc n) et la liste (1- n). Et puisque chaque élément d’une liste peut aussi être une liste, on peut utiliser ces listes pour construire un arbre syntaxique d’un programme.

Voilà donc une des différences fondamentales entre le Lisp et les autres langages de programmation : en Lisp, le code source est une représentation explicite de son arbre syntaxique, alors que dans les autres langages, cet arbre, généralement construit et manipulé dans le compilateur uniquement, est inaccessible de l'extérieur.

Voici un second exemple en Common Lisp qui affiche une liste de courses :

(defun courses (ingredients)
  "Affiche une liste de courses."
  (if (null ingredients)
      (princ "Je n’ai rien à acheter")
      (progn
        (format t "J’ai ~D ~A à acheter : "
                (length ingredients)
                (if (> (length ingredients) 1) "choses" "chose"))
        (labels ((p (ingredients)
                   (format t "~(~A~)" (first ingredients))
                   (case (length ingredients)
                     (1 (princ "."))
                     (2 (princ " et ") (p (rest ingredients)))
                     (otherwise (princ ", ") (p (rest ingredients))))))
          (p ingredients))))
  (fresh-line))

(Note aux connaisseurs : je sais que j’aurais pu me contenter d’un unique appel à la fonction format pour afficher cette liste, mais la chaîne de format deviendrait très vite absconse.)

Appeler cette fonction depuis du code nécessite cependant d’utiliser un opérateur spécial, quote, pour indiquer une donnée à utiliser telle quelle : un symbole qui ne désigne pas une variable ou une liste qui n’est pas un appel de fonction. Ici, il faut que la liste de courses soit traitée comme une liste au lieu d’un un appel de fonction (notez l’apostrophe devant chaque liste, qui est la forme abrégée de quote), comme ceci :

* (courses '())
Je n’ai rien à acheter

* (courses '(œufs))
J’ai 1 chose à acheter : œufs.

* (courses '(œufs chocolat))
J’ai 2 choses à acheter : œufs et chocolat.

* (courses '(œufs chocolat sucre farine))
J’ai 4 choses à acheter : œufs, chocolat, sucre et farine.

Le fait qu’un programme Lisp soit représenté à l’aide de sa propre représentation de listes et d’arbres est aussi appelé homoiconicité. Cette propriété, partagée par très peu de langages de programmation, rend ainsi trivial la génération de code. Par conséquent, Lisp bénéficie d’un système de macros parmi les plus puissants de tous des langages de programmation.

Emacs et Emacs Lisp : ma première expérience de Lisp

J’avais déjà utilisé un peu Emacs quand j’étais en école d’ingénieurs, mais je ne me voyais pas m’en servir autrement qu’après avoir tapé M-x viper-mode car j’avais beaucoup trop l’habitude des touches de vi. Spacemacs me retirait une grosse épine du pied en proposant un Emacs « vimifié » ; j’étais donc prêt à me refaire une nouvelle première impression. Et j’allais avoir une semaine de vacances devant moi pendant lesquelles j’aurais suffisamment de temps pour explorer sérieusement Emacs.

Je me souviens donc bien comment je m’étais installé dehors, un après-midi, avec mon PC portable sur les genoux, pour lire le manuel d’Emacs Lisp.

Les extensions d’Emacs, mais aussi une grosse partie de l’éditeur lui-même, sont codés en Emacs Lisp. Ce langage est un dérivé d’un dialecte assez ancien de Lisp, Maclisp, qui date des années 1960. Ce qui explique certains de ses pièges, comme le fait que les variables aient par défaut une portée dynamique plutôt que lexicale (ce qui est cependant en train de lentement changer). La quantité de code Emacs Lisp qui circule de nos jours signifie que tout changement majeur, comme une forme de programmation concurrente, doit être introduite en procédant à tâtons pour éviter de casser le code existant.

Pour cette raison, les détracteurs disant qu’Emacs a davantage les fonctionnalités d’un système d’exploitation que ceux d’un éditeur de texte ont à mon avis partiellement raison. Emacs est en effet un interpréteur Lisp doté de fonctions conçues pour éditer du texte, mais il est capable de bien plus que ça. Autrement dit, Emacs est une machine Lisp moderne.

J’utilise maintenant énormément Org-mode au travail et je me suis fait quelques petits scripts en Emacs Lisp pour automatiser certaines tâches administratives fastidieuses. Étant contraint à Windows au bureau, système sur lequel Emacs a été porté, j’apprécie beaucoup cet accès facile à un Lisp tout à fait honorable. Et en parallèle, je suis devenu encore plus frustré par les outils informatiques dépourvus du moindre mécanisme d’extension.

Toujours est-il que l’omniprésence d’Emacs Lisp dans Emacs font de cet éditeur un des meilleurs outils pour programmer non seulement en Emacs Lisp, mais dans n’importe quel Lisp de manière générale.

Common Lisp : l’héritier des Lisp traditionnels

Le Common Lisp a été l’étape suivante dans mon aventure. Mon tutoriel a été le livre Practical Common Lisp de Peter Seibel, qu’on peut lire gratuitement en ligne ou acheter en version papier. Et quand on code, le Common Lisp HyperSpec est accessible en ligne et constitue le manuel de référence du langage.

Ce langage est le fruit d’un effort de standardisation d’un Lisp remontant aux années 1980. Ces efforts ont abouti à une norme ANSI publiée en 1994 et restée inchangée depuis. Le but du jeu était de créer un Lisp couvrant les fonctionnalités de plusieurs dialectes incompatibles entre eux. Par conséquent, le langage n’est certes pas aussi « pur » qu’un Scheme et comporte quelques petites incohérences et de petits défauts ; la syntaxe de la macro loop et celle de la fonction format étant les aspects les plus controversés. Néanmoins, il est tout à fait apte à être utilisé pour des applications industrielles et j’ai même vu un livre de finance dont les exemples de code sont en Common Lisp. Paul Graham explique par exemple comment, dans les années 1990, il a monté une start-up d’hébergement de boutiques en ligne, Viaweb, en Lisp, dans son article « Beating the Averages ».

Son écosystème riche, son système de programmation orientée objet, CLOS, ainsi que son système de gestion d’erreurs qui propose une approche intéressante aux exceptions tels qu’on les trouve en C++, Java ou Python font de ce Lisp un langage qui vaut le détour.

Clojure : un Lisp pour la JVM

Clojure, quant à lui, est un Lisp plus récent, conçu pour s’intégrer dans l’écosystème Java. Il s’exécute en effet exclusivement dans la JVM et le langage est bien entendu doté de primitives pour interagir avec des classes Java. En résumé, c’est une façon de faire du Java sans subir la syntaxe verbeuse ni l’orienté objet à outrance du Java.

Son Java interop m’a déjà bien servi : j’avais eu besoin un jour de déboguer un document Word (au format docx), généré par un logiciel mais que Word déclarait corrompu. Pour cela, j’ai utilisé la bibliothèque Java docx4j, quelques fonctions en Clojure mais surtout le REPL de Clojure pour explorer la structure du document et trouver le problème. In fine, il s’avérait juste que deux éléments XML avaient le même identifiant.

Il existe aussi une variante de Clojure appelée ClojureScript, qui comme son nom l’indique tourne non pas sur la JVM mais dans un environnement JavaScript. Clojure et ClojureScript utilisés ensemble permettent donc de partager du code entre les côtés serveur et client dans un projet Web, mais je n’ai pas encore eu l’occasion de mettre cela en pratique. Cela étant, le développement en ClojureScript pour cibler un navigateur est un peu plus fastidieux car l’accès à un REPL est plus compliqué à mettre en place qu’avec Clojure.

Parmi les aspects les plus intéressants du langage figurent les lazy seqs, c’est-à-dire des séquences, pouvant être infinies, qui sont évalués de façon paresseuse. On peut par exemple définir une fonction qui génère la suite (infinie) de Fibonacci, puis n’en demander que le dixième terme ; ceci provoque le calcul des dix premiers termes uniquement.

Mais il y a plusieurs aspects qui me rebutent dans ce langage et qui me font hésiter à en faire mon outil de choix.

Premièrement, du fait de son adhérence forte à Java, certains des reproches qu’on fait à Java s’appliquent aussi à Clojure. Lancer un REPL, par exemple, devient vite lent et gourmand en RAM : dans un projet vierge, ça démarre en une demi-seconde avec déjà 294 Mo de RAM occupés, mais dans un projet plus avancé avec une quinzaine de bibliothèques en dépendances, ça monte à 678 Mo de RAM après près de deux minutes de compilation. Et dans mon environnement Emacs, il n’est pas rare de voir des sous-processus Java monter à plus de 2 Go de RAM !

Clojure me semble plutôt marcher sur les plates-bandes traditionnelles de Java, qui sont les gros logiciels (trop) complexes qu’on démarre et arrête généralement en même temps que sa machine hôte. Je ne me vois pas faire de scripts avec, simplement à cause du temps de démarrage de la JVM qui interdit de fait ce type d’usages.

Deuxièmement, le fait qu’il soit distribué sous la licence Eclipse Public License (EPL) 1.0 me semble être un choix malheureux, étant donné qu’il faut nécessairement distribuer le binaire (.jar) du cœur de Clojure avec tout programme Clojure. Or cette licence connue pour poser problème avec d’autres licences libres comme la GPL.

Le langage est en lui-même intéressant et a peut-être permis d’introduire du Lisp dans des environnements traditionnellement prompts à se ruer sur Java pour tout projet. Mais ce ne sera pas le langage que je choisirai en premier pour un nouveau projet car ça reste une « usine à gaz ».

Haskell, le parfait anti-Lisp dans sa syntaxe

Certains ouvrages sur Lisp que j’ai lus avant d’écrire ce billet mentionnaient Haskell, presque comme s’il s’agissait d’un Lisp lui aussi. Il s’agit d’un langage fonctionnel, une approche qui se prête bien au Lisp. Par curiosité, j’ai voulu essayer.

Le tutoriel Web sur le site officiel, entièrement interactif, m’a particulièrement impressionné. Une autre très bonne ressource qui m’a servi pour essayer le Haskell est le livre Learn You a Haskell for Great Good! de Miran Lipovača (disponible gratuitement en ligne).

Mais j’ai du mal avec sa syntaxe. La quasi-absence de parenthèses est très déroutante car elle oblige le lecteur à se rappeler des règles d’associativité. Les appels de fonction n’échappent pas à la règle ; le langage doit donc prévoir un opérateur, $, pour appliquer une fonction avec une associativité à droite plutôt qu’à gauche ; le tout est un obstacle à un code intelligible. Ensuite, la nécessité d’indenter le code de façon très précise, ce qui revient à donner une importance syntaxique aux blancs (comme en Python), est un autre aspect avec lequel j’ai personnellement beaucoup de mal. Le haskell-mode d’Emacs facilite un peu les choses, mais j’ai tout de même le sentiment que ce langage n’est pas fait pour moi.

Néanmoins, je perçois l’influence du Lisp dans le fait que l’opérateur servant à ajouter un élément au début d’une liste (:) s’appelle « cons », comme la fonction du même nom en Lisp.

J’accorderai peut-être une seconde chance plus tard à ce langage, mais dans l’immédiat, je préfère le confort et l’inambiguïté des S-expressions.

Retour à Common Lisp

En recherchant des ressources sur la programmation en Emacs Lisp, je suis tombé sur un petit tutoriel ludique dans lequel on programme un petit jeu d’aventure textuel en Lisp. Ce tutoriel est par ailleurs une bonne démonstration de ce qu’il est possible de construire avec des macros Lisp.

L’auteur, Conrad Barski, a ensuite publié le très bon ouvrage Land of Lisp, qui va dans le prolongement de ce petit tutoriel : tous les exemples sont des jeux. Cette approche convient particulièrement bien à un public non informaticien et permet d’aborder des thématiques que je ne ne vois pas souvent dans des introductions à des langages de programmation, comme par exemple la programmation d’intelligences artificielles pour des jeux de plateau. Grâce à ce livre, Nausicaa a adopté le Common Lisp et est en train d’écrire un jeu dans ce langage ; ce qui est de très bonne augure, car cela nous fait un langage de programmation en commun que nous apprécions ensemble.

Peu avant de partir en vacances d’été, je me suis amusé, en guise de petit défi, d’écrire un solveur de picross. J’avais choisi Common Lisp plutôt que Clojure car Common Lisp ne dispose pas des lazy seqs de Clojure. C’est un projet qui s’est avéré beaucoup plus intéressant qu’à première vue et dont je parlerai sûrement dans un billet futur.

Par ailleurs, Common Lisp étant lui-même une spécification, il existe en fait plusieurs environnements Lisp qui portent des noms différents : parmi eux, il y a GNU CLISP, SBCL, Clozure CL (à ne pas confondre avec Clojure) et ABCL, ce dernier ayant la particularité de tourner sur la JVM.

Racket ou la programmation orientée langages

Ma dernière destination dans mon voyage dans l’univers des Lisp est Racket.

Racket est en fait un langage dérivé de Scheme, qui est lui-même un Lisp qui a vu le jour dans les années 1970 au MIT. Racket est conçu à la fois comme un outil de recherche et comme un support pédagogique en théorie de langages de programmation (d’où son nom d’origine, PLT Scheme – PLT pour Programming Language Theory).

La principale caractéristique de Racket est d’offrir un cadre pour définir, dans le compilateur Racket, n’importe quel langage dédié. Bien que les autres Lisp se prêtent très bien à la création de tels langages dédiés, ces langages sont la plupart du temps tenus à respecter la syntaxe des S-expressions. Racket, quant à lui, permet de créer des langages qui s’affranchissent de cette limitation : ainsi, on peut très bien créer des langages où on peut exprimer le produit 7 × 191 par une notation infixe (7 * 191) plutôt que préfixe ((* 7 191)).

Ainsi, Racket pousse la notion de programmation orientée langages le plus loin possible. Plutôt que d’exprimer une solution à un problème directement dans un langage de programmation, on définit d’abord un langage plus concis dans lequel on exprime le problème, on écrit un programme transformant les expressions de ce nouveau langage en code Racket, puis on compile ce nouveau langage.

La programmation orientée langages a lui-même de nombreuses applications. Il existe par exemple un langage d’édition vidéo. Le studio Naughty Dog a également utilisé des mini-langages créés dans Racket pour scripter l’intrigue et l’intelligence artificielle dans certains de ses jeux (voir par exemple cette présentation par le CTO de l’entreprise).

J’ajouterais aussi que même si personnellement, je préfère Emacs et son racket-mode pour des raisons de confort, l’IDE de référence, DrRacket est bien conçu et est un outil qu’on peut mettre entre toutes les mains, notamment de débutants. En particulier, le livre How to Design Programs par Matthias Felleisen et al. utilise Racket comme outil pédagogique.

Je n’ai pas encore eu l’occasion de me faire la main sur Racket avec un projet sérieux, mais je vois énormément de potentiel dans un langage qui a l’air à la fois très puissant et très accessible à des débutants.

Conclusion

Ma découverte fortuite d’Emacs m’a permis d’explorer en deux ans un univers entier de langages de programmation que je n’aurais pas eu la curiosité d’étudier sinon. Je suis conscient que je n’ai pas encore exploré Scheme, en dépit de ma possession d’un exemplaire papier de Structure and Interpretation of Computer Programs de Harold Abelson et Gerald J. Sussman (consultable gratuitement en ligne), ni Guile, entre autres utilisé pour scripter divers logiciels GNU. Mais je pense néanmoins avoir au moins fait le tour des langages les plus représentatifs de ce qu’est la famille Lisp aujourd’hui.

Ces nouveaux langages pour moi ont été l’occasion de me lancer dans certains projets personnels dont je parlerai sûrement dans d’autres billets de blog : par exemple, j’ai fait un robot générateur de texte à base de chaînes de Markov ou un solveur de Picross assez efficacement ; dans les deux cas, mon tout premier prototype était opérationnel en l’équivalent d’une ou deux soirées.

Me voilà donc converti au Common Lisp, voire peut-être au langage Racket si mes expériences dans ce langage-là sont concluants.

Pour terminer, je me permets de citer Eric S. Raymond, qui, dans son essai intitulé « How To Become A Hacker », écrit :

LISP is worth learning for a different reason — the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot.

Thèse d’histoire en LaTeX : quelques trucs et astuces

 x0r   0
latex histoire thèse tex

Dans mon précédent billet sur la thèse de Nausicaa préparée en LaTeX, je vous avais promis de partager quelques « astuces [de LaTeX] que j’ai découvertes au fil de l’eau ». Ce billet vise donc à tenir cette promesse.

Ce que je présente ici sont quelques personnalisations, surtout de forme, qui étaient à la fois non-triviales (c’est-à-dire qu’il n’existait pas de commandes dans la documentclass memoir pour le faire facilement) et indispensables pour que la thèse puisse être acceptée et soutenue. C’est en outre le fruit de la lecture de moult références, sur TeX, LaTeX et BibLaTeX notamment.

Je vous propose donc quelques « recettes » de LaTeX, commentées comme il se doit pour ne pas me contenter d’être une compilation de bouts de code à copier-coller dans un projet LaTeX et illustrer comment on peut construire des fonctionnalités avancées. C’est pourquoi notre progression se fera dans un ordre croissant de difficulté.

Préliminaires

Les extraits de code que je présente partent du principe que :

  • votre document utilise la documentclass memoir (et non pas book) ;
  • et votre fichier .tex principal inclut, dans son préambule, un fichier .sty contenant toutes vos commandes de personnalisation (de forme) à l’aide d’un \usepackage.

Comme je l’avais déjà expliqué dans mon précédent billet, memoir est strictement supérieur à book car le premier propose davantage de possibilités de personnalisation que le second. Le mode d’emploi de memoir est par ailleurs très bien fait et je recommande fortement au moins de le survoler.

Citations au format ISO 690

L’université de la Sorbonne exige que les références bibliographiques soient au format NF Z 44-005. Il s’agit d’une norme, annulée depuis, et remplacée par la norme ISO 690.

BibLaTeX embarque un style ISO 690, mais à l’époque où Nausicaa finissait sa thèse, ce module avait deux problèmes.

Tout d’abord, il manquait encore les traductions françaises pour les petits bouts de texte comme « supervisé par » ou « sous la direction de ». Du moins, ce n’était pas le cas dans la version 0.3.1 que nous utilisions à ce moment-là. Heureusement, ces traductions ont été introduites depuis et devraient être disponibles d’emblée à partir de la version 0.4.0.

Enfin, Nausicaa voulait aussi que les titres des articles apparaissent entre guillements. Pour cela, le seul correctif est de fournir à BibLaTeX un style de bibliographie personnalisé, dérivé du style officiel mais remplaçant le formatage des champs adéquats.

Pour cela, on place un fichier iso-custom.bbx dans le même répertoire que le fichier principal, avec le contenu suivant :

\ProvidesFile{iso-custom.bbx}[2020/07/08 v0.1 biblatex bibliography style]

\RequireBibliographyStyle{iso}

\DeclareFieldFormat[article,periodical,inproceedings]{title}{\mkbibquote{#1}}

Sommaire au début et table des matières à la fin

Le format de la thèse exigeait un sommaire et une table des matières : le sommaire étant au début et ne reprenant que les \part et les \chapter et la table des matières étant à la fin et allant jusqu’au niveau \subsubsection. Or LaTeX ne fournit que la commande \tableofcontents pour insérer une table des matières. Pour le sommaire, il faut ruser un peu.

Tout d’abord, on positionne le compteur tocdepth à 3 pour que la table des matières fasse apparaître les titres jusqu’au niveau \subsubsection.

\setcounter{tocdepth}{3}

Ensuite, on définit une commande \printshorttoc qui peut être utilisé dans le fichier .tex principal pour composer le sommaire. La commande fonctionne comme suit :

  1. Sauvegarder l’ancien nom de la table des matières, défini dans la macro \contentsname (par défaut « Table des matières ») pour le changer temporairement en « Sommaire ». De même pour la valeur du tocdepth.
  2. Positionner temporairement le compteur tocdepth à 0 pour se restreindre aux titres de niveau \chapter dans le sommaire.
  3. Réduire sensiblement les espacements verticaux introduits juste avant chaque partie ou chapitre (longueurs définies dans \cftbeforepartskip et \cftbeforechapterskip) : dans le cas contraire, on perd en effet pas mal de place inutilement sur la page.
  4. Imprimer le sommaire avec \tableofcontents.
  5. Enfin, restaurer le \contentsname et le tocdepth.

La commande \printshorttoc est définie comme suit :

\newcommand{\printshorttoc}{%
  \let\origcontentsname\contentsname
  \@tempcnta=\value{tocdepth}
  \renewcommand*{\contentsname}{Sommaire}
  \setcounter{tocdepth}{\z@}
  {%
    \cftbeforepartskip=0.55\cftbeforepartskip
    \cftbeforechapterskip=0.55\cftbeforechapterskip
    % 
    \tableofcontents%
  }%
  %
  \renewcommand*{\contentsname}{\origcontentsname}
  \setcounter{tocdepth}{\@tempcnta}
}

Un \chapter* et \section* améliorés

Un problème récurrent est l’ajout de sections non numérotées mais qui doivent tout de même apparaître dans le sommaire et la table des matières. Or, même dans la documentclass memoir, les commandes \chapter* et \section* ne le font pas.

Une solution possible est de ne plus utiliser les versions étoilées de ces commandes et d’y substituer les siennes. Concrètement, il faut faire trois choses :

  1. Composer la section au bon niveau (chapitre, section…) ;
  2. Ajouter une ligne dans la table des matières (et si on utilise le package hyperref, comme c’était le cas, il faut invoquer la commande \phantomsection immédiatement avant comme expliqué sur StackOverflow) ;
  3. Enfin, réinitialiser les marqueurs gauche et droite (le texte qui se trouve par défaut en haut de chaque page pour rappeler le titre du chapitre et de la section où on se trouve).

Voici le code (copieusement commenté, parce que le langage TeX devient vite illisible) :

\def\@mark@unnumbered@chapter#1{\markboth{#1}{}}
\def\@mark@unnumbered@section#1{\markright{#1}}
\def\@unnumberedsection#1#2{%
  % Composer le \chapter* ou \section* (en fonction de la valeur du paramètre 1)
  \expandafter\csname #1\endcsname*{#2}%
  % Ajout de l’entrée dans la TDM
  \phantomsection%
  \addcontentsline{toc}{#1}{#2}%
  % Appel de \@mark@unnumbered@chapter ou \@mark@unnumbered@section pour
  % réinitialiser les marqueurs
  \expandafter\csname @mark@unnumbered@#1\endcsname{#2}%
}

\newcommand{\addchapter}[1]{\@unnumberedsection{chapter}{#1}}
\newcommand{\addsection}[1]{\@unnumberedsection{section}{#1}}

Métadonnées personnalisées

Afin de composer une belle page de garde avec un titre, le nom de l’auteur et d’autres métadonnées, LaTeX propose les commandes \title, \author et \date, entre autres.

Mais sur la page de garde d’une thèse, doivent également figurer d’autres informations : l’université, l’année de la thèse, le grade visé, la spécialité, les noms du directeur et des membres du jury, etc.

Mon approche consistait donc à redéfinir la commande \maketitle pour faire figurer ces informations. Mais pas question de les coder en dur : afin de faire les choses proprement, on va simplement définir des champs supplémentaires.

Cela nécessite deux choses : une macro qui compose la valeur du champ, initialisée à une valeur par défaut (ou une séquence de commandes affichant un avertissement sur la console, comme le fait \title) et une commande pour affecter une nouvelle valeur à cette macro. Pour un champ appelé foo, on appelle \@foo le « getter » et \foo le « setter », lesquels peuvent être définis ainsi :

\newcommand\@foo{%
  \@latex@warning@no@line{No \noexpand \foo given}}
\newcommand\foo[1]{\gdef\@foo{#1}}

Étant donné le nombre de répétitions de « foo » dans la définition de ces deux macros, on pourrait imaginer une commande qui, avec une invocation comme \DefineMetaData{foo}, ferait ces deux définitions pour nous. Mais comme avec la technique vue ci-dessus, il faudrait une surabondance de \expandafter et de \csname #1 \endcsname. Je n’ai pas eu la patience d’élaborer une telle commande à temps pour le rendu de la thèse, donc je vous laisse proposer une solution.

Notes de bas de page

La numérotation des notes de bas de page est régie par le compteur footnote.

Normalement, LaTeX réinitialise bien les numéros de notes de bas de page au début de chaque chapitre, à condition d’utiliser \chapter. Mais ce n’est pas toujours suffisant, pour deux raisons.

Premièrement, parce que dans la thèse, les parties commencent par une introduction qui précède le début du premier chapitre de la partie. Les numéros des notes de ces introductions poursuivaient alors à partir du chapitre précédent…

Deuxièmement, parce que pour une raison obscure, ce compteur n’était pas non plus réinitialisé lorsqu’on utilise \chapter dans le \frontmatter ou le \backmatter. Ce qui est embêtant lorsqu’il y en a pour une cinquantaine de pages de contenu liminaire, introduction comprise…

Pour corriger cela, on redéfinit \chapter et \part pour s’assurer de remettre ce compteur footnote à zéro quoi qu’il arrive :

\let\orig@chapter\chapter
\def\chapter{\setcounter{footnote}{\z@}\orig@chapter}
\let\orig@part\part
\def\part{\setcounter{footnote}{\z@}\orig@part}

Conclusion

Il va sans dire que personnaliser LaTeX n’est pas forcément à la portée de tout le monde : une partie de la complexité est due à l’art de la typographie, qui est un art en soi ; l’autre partie est due au langage TeX.

TeX, au fond, est en effet un langage de macros ; cette propriété lui permet de facilement bâtir des langages dédiés très puissants entre de bonnes mains. Mais comme tous les langages de ce type, le test et le débogage de macros personnalisés peut vite virer au cauchemar. C’est pour cette raison que dans des langages comme le C ou le Lisp, par exemple, la règle no 1 de l’élaboration de macros est d’essayer de s’en passer.

C’est pourquoi une compréhension simultanée de TeX et de LaTeX est indispensable si on veut des documents qui sortent de l’ordinaire. Plus exactement, il faut comprendre à la fois le fonctionnement de TeX en tant que langage de programmation (c’est-à-dire les règles syntaxiques, les règles d’expansion…) et le fonctionnement de TeX en tant que typographe (comme la différence entre les modes horizontaux et verticaux, l’algorithme de césure…). Le TeXbook de Donald Knuth explique très bien les deux aspects de TeX et est donc un ouvrage à avoir sous la main à tout moment. Après tout, on a vite fait de sortir du domaine de la typographie pour rentrer dans celui de la programmation.

Une thèse d'histoire en LaTeX

 x0r   0
latex histoire thèse

Ma bien-aimée Nausicaa a soutenu aujourd’hui sa thèse d’histoire médiévale.

Pendant les quatre ans qu’ont pris son travail, j’ai été à ses côtés pour l’aider sur le plan technique de deux façons. D’abord en développant pour elle les outils informatiques lui permettant d’effectuer des études statistiques sur des affaires judiciaires médiévales. Mais aussi en la convaincant de rédiger sa thèse avec LaTeX.

Ce logiciel, qu’on ne présente plus depuis des décennies dans les univers des mathématiques, de la physique ou de l’informatique, est un choix beaucoup plus atypique dans le milieu des sciences humaines. Néanmoins, le bilan est positif car elle pense que LaTeX lui a fait gagner un an sur une phase de rédaction qui lui a pris un an et demi.

Je vous propose donc un retour d’expérience de la rédaction de sa thèse, de mon propre point de vue, que je scinde en deux billets. Dans ce billet, nous verrons les motivations, le choix des outils. Dans un billet suivant, je traiterai de quelques astuces que j’ai découvertes au fil de l’eau.

Ce qui l’a amenée à utiliser LaTeX

Le choix des outils est peut-être un des aspects les plus effrayants de ce type de projet. Ces choix sont difficiles et il faut les assumer pour au moins trois ou quatre ans, voire jusqu’à six ans en histoire. Plusieurs facteurs ont fini par amener Nausicaa à adopter LaTeX pour sa thèse.

Les outils WYSIWYG sont inadaptés pour les documents de cette envergure

D’une part, les outils dits WYSIWYG (What You See Is What You Get) qu’elle a connus jusque-là montraient clairement leurs limites pour un projet comme le sien.

Beaucoup de ces logiciels, comme Microsoft Office ou Scrivener, sont payants. Or elle n’était pas disposée à payer quoi que ce soit, surtout qu’elle avait l’habitude de LibreOffice. Quant au modèle d’abonnement que propose Office 365, c’était hors de question.

LibreOffice, ensuite, s’est disqualifié tout seul. Alors qu’elle n’en était qu’à la moitié de la rédaction de son mémoire de stage, LibreOffice s’est mis soudainement à planter systématiquement à l’ouverture de son document. Sueurs froides garanties ! Il a fallu que j’ouvre son fichier sur ma machine, qui avait une version différente de LibreOffice, et que je le sauvegarde à nouveau pour qu’elle puisse y retrouver l’accès. Donc si LibreOffice avait eu autant de mal à gérer un mémoire de 100 pages, impossible de prédire ce qui allait se passer avec un document six fois plus long…

De manière plus générale, les logiciels WYSIWYG essayent tous d’être les plus complets possibles, pour finir par être le seul logiciel utilisé du début à la fin du processus rédactionnel. Ils ouvrent le document de travail en lecture-écriture, ce qui introduit un risque de corruption des données, et utilisent des formats obscurs et parfois horriblement complexes. Par exemple, saviez-vous que la norme ISO/IEC 29500, qui codifie entre autres le format .docx, est composée de quatre volumes totalisant 6 766 pages ?

Le moindre problème avec l’outil, ou la moindre mise à jour, apporte donc avec lui le risque de perdre l’accès à son texte. Même le découpage de son document en autant de fichiers par chapitre n’éliminera pas entièrement ce danger.

Ensuite, il faut y ajouter un bon outil de gestion de bibliographie, comme Endnote, payant et propriétaire ou Zotero, gratuit et libre. Mais là encore, le risque de perdre sa bibliographie est tout aussi inacceptable que celui de perdre le reste de son travail. D’autant plus quand ladite bibliographie se compte en centaines d’entrées, comme toute bonne thèse d’histoire qui se respecte…

Elle connaissait déjà le principe d’un langage de « markup » comme HTML

En revanche, les outils qu’on oppose généralement aux WYSIWYG n’ont pas ce problème car le workflow est différent. Le principe est en effet le suivant : composer un fichier texte brut, structuré en suivant les règles d’un langage informatique, dans un premier logiciel ; puis utiliser un second programme qui interprète ce fichier, pour obtenir un rendu final (généralement sous forme de PDF).

Même si on ne voit pas tout de suite le résultat final de son travail à l’écran, l’avantage majeur est qu’un problème avec un logiciel comme LaTeX ou biblatex ne font pas perdre son travail ; juste la faculté de prévisualiser le résultat final. Et un problème avec un éditeur de texte, en plus d’être extrêmement rare, n’est pas une fatalité non plus : dans les cas les plus extrêmes, on peut changer d’éditeur.

Nausicaa avait déjà fait beaucoup de HTML et de CSS dans le passé. Ainsi, non seulement elle connaît bien le principe de rédiger un texte dans un langage source avec un autre outil que celui utilisé pour visualiser le résultat, mais elle maîtrise également l’idée d’une stricte séparation du fond et de la forme. Rédiger un document en LaTeX lui demandait donc juste de se familiariser avec le langage.

Je lui ai beaucoup parlé de LaTeX

Je dois ensuite admettre que j’ai fait un peu de « lobbying » de mon côté pour la convaincre d’utiliser LaTeX plutôt qu’un cliquodrome.

J’utilise en effet LaTeX depuis plus de douze ans. En prépa, je l’utilisais pour préparer la quasi-totalité de mes devoirs maison, ce qui ne manquait jamais de surprendre mes enseignants. En école d’ingénieurs, je m’en servais pour mes rapports de projet et de stage mais aussi pour mes notes de cours. Plus tard, j’ai composé mes CV et mes lettres de motivation, toujours avec LaTeX. Et j’ai eu de multiples occasions, chez différents employeurs, de faire de la rétro-ingénierie de chartes graphiques d’entreprise en Word pour générer des documents respectant cette même charte mais en LaTeX. Maintenant, je l’utilise encore, principalement pour mes courriers.

Ces douze ans d’expérience m’ont donc permis d’assurer le support technique LaTeX pour Nausicaa et de l’aider pour les choses plus compliquées à faire dans ce langage, comme une couverture personnalisée ou les aspects plus délicats de la mise en forme.

Enfin, peu avant le début de sa thèse, je lui avais également offert le livre LaTeX appliqué aux sciences humaines, de Maïeul Rouquette et que je recommande vivement. L’ouvrage est complété par le blog de l’auteur, qui sert aussi d’erratum sur certains sujets évoqués dans son ouvrage (comme l’indexation).

Elle a pratiqué LaTeX à l’université

Mais c’est une formation LaTeX qui l’a vraiment séduite. Il s’agissait d’une formation doctorale à la Sorbonne, dispensée par un maître de conférences en musicologie. Non seulement parce qu’elle pratiquait directement le langage LaTeX sur une machine, mais aussi parce que la formation était plutôt exhaustive et, visant un public de chercheurs, traitait de biblatex.

Cette formation était plutôt bienvenue pour elle, parce que je n’aurais jamais eu le temps de tout lui montrer moi-même (c’est aussi pour ça que je lui avais acheté un livre, après tout). Et je pense que voir une démonstration de LaTeX par quelqu’un d’autre que moi a été déterminant dans son choix final.

LaTeX lui sert aussi pour ses présentations

Pour finir, LaTeX a aussi l’avantage de ne pas être qu’un concurrent à Word.

En 2016, pour une communication scientifique, Nausicaa avait préparé des planches sur Microsoft PowerPoint. Le moment venu de la présentation, elle ouvre le fichier sur le PC à sa disposition et patatras ! les couleurs n’étaient pas bonnes, le rendu était horrible et la présentation défigurée. Elle avait en effet préparé ses planches sur un PowerPoint plus récent que celui du PC de la salle. Il va de soi qu’elle a mal vécu cet incident.

Depuis, elle a pris l’habitude de préparer ses présentations sur Overleaf, en utilisant beamer. Avec le raisonnement que puisque le format de sortie est un PDF, ça marchera partout. Et elle m’a dit avoir gagné beaucoup de temps avec cette solution par rapport à PowerPoint, car elle peut se concentrer davantage sur le contenu.

LaTeX lui a donc servi non seulement pour sa thèse, mais aussi pour les « slides » de sa soutenance. Il ne manquerait plus que LaTeX fasse le café !

Choix d’outils

Choisir LaTeX plutôt que des traitements de texte traditionnels implique de faire plusieurs choix tout aussi importants : la distribution et le moteur TeX, l’éditeur dans lequel on prépare le texte source, le système de gestion de versions, la « documentclass » et les autres aides à la préparation de documents.

Installer ShareLaTeX sur mon serveur : un échec

À l’origine, puisqu’elle utilisait déjà ShareLaTeX (actuellement Overleaf) pour ses présentations et que cet outil est open source, je m’étais mis en tête de déployer localement ShareLaTeX sur mon serveur domestique.

Malheureusement, la seule méthode de déploiement prise en charge est Docker. Or Docker sur FreeBSD, ça ne marche pas très bien. J’ai d’abord essayé de déployer Overleaf dans une « jail » tout en me passant de Docker, mais j’ai abandonné devant le nombre ahurissant de dépendances qu’il fallait installer et gérer à la main. Je suis même allé jusqu’à installer une Ubuntu Server sur une VM bhyve (dont j’ai déjà parlé dans ce billet), pour installer cette image Docker dedans. Le tout sans succès non plus.

J’ai donc abandonné cette idée, et j’ai choisi de déployer une distribution LaTeX et un éditeur adapté sur le PC de Nausicaa.

TeX Live comme distribution LaTeX, même sous Windows

Tout d’abord, plutôt que MiKTeX, qui semble être la distribution recommandée sous Windows, j’ai préféré installer TeX Live pour qu’elle ait la même chose que moi et mes PC sous Linux. TeX Live fonctionne en effet très bien sous Windows et est déjà la distribution de choix pour les dérivés d’UNIX.

Quant au moteur LaTeX, plutôt que le moteur TeX d’origine, nous avons préféré partir sur XeTeX pour plusieurs raisons :

  • c’est à la fois ma préférence personnelle et celle de Maïeul Rouquette ;
  • ce moteur gère nativement l’Unicode et accepte par défaut des fichiers source en UTF-8 ;
  • et enfin, ce moteur gère les polices TrueType (TTF) et OpenType (OTF) et leurs fonctions avancées nativement, comme les ligatures. Le moteur TeX, en revanche, fonctionne avec les polices au format MetaFont, qui ne sont pas aussi répandues.

Gnuplot, pour de jolis graphiques

La portée de son travail allait amener Nausicaa à générer des graphiques tirées de séries statistiques. Je lui ai donc proposé d’utiliser Gnuplot, parce que je connaissais déjà ce logiciel, parce que le résultat est joli et surtout parce que les graphiques sont produits à l’aide de scripts. Ce qui permet donc aux figures d’avoir une apparence cohérente, mais aussi d’être gérées comme du code source.

Éditeur LaTeX : en privilégier un conçu pour la programmation

Avant le début de sa thèse, j’ai passé beaucoup de temps à essayer plusieurs éditeurs de texte orientés LaTeX comme TeXmaker, TeXstudio ou TeXworks. À l’époque où j’avais fait ces tests, c’est-à-dire en 2015, je n’étais satisfait par aucun de ces outils car j’y percevais d’importantes lacunes (ça a peut-être changé depuis).

Même si latexmk simplifie énormément la compilation de documents LaTeX, le fait qu’elle utilise Gnuplot signifiait que j’allais tout de même avoir besoin de personnaliser facilement l’ensemble des étapes nécessaires pour compiler le document PDF à partir des fichiers source. Or, aucun de ces éditeurs ne me permettait de paramétrer cette chaîne de compilation d’une manière satisfaisante.

Je lui ai donc proposé d’utiliser l’éditeur Visual Studio Code de Microsoft. À l’époque, c’était relativement nouveau, donc le choix était risqué. Mais il m’a donné une très bonne première impression néanmoins. Après avoir installé l’extension LaTeX Workshop (qui elle, était vraiment toute nouvelle à l’époque), Code devient un éditeur LaTeX avec une ergonomie agréable. La prévisualisation PDF a le bon goût de s’ouvrir dans une nouvelle fenêtre, contrairement aux éditeurs LaTeX qui l’affichent généralement dans la même fenêtre que le code. Étant donné qu’elle a muni son PC d’un second écran en mode portrait, elle peut donc facilement afficher côte à côte le code et le résultat, chacun ayant son moniteur dédié.

Le point faible de cette solution est que LaTeX Workshop était assez bugué à l’époque. Si bien qu’il fallait, de temps en temps, redémarrer VS Code et supprimer l’intégralité des fichiers auxiliaires générés par LaTeX pour remettre les choses d’aplomb. Par ailleurs, Nausicaa était très réticente à installer les mises à jour de VS Code ou de LaTeX Workshop, parce qu’une de ces mises à jour lui avait causé des problèmes.

Les problèmes se manifestaient généralement par des fichiers .aux tronqués ou corrompus. Une fois, j’avais dû aller dans le Gestionnaire des tâches pour arrêter des processus LaTeX qui traînaient. Mais je pense avoir l’explication : je crois que sa version de LaTeX Workshop omettait de bloquer la commande de compilation quand une tâche de génération est déjà en cours, si bien qu’on peut lancer accidentellement plusieurs tâches concurrentes sur le même projet. Et comme LaTeX est plus lent sous Windows que sous Linux et qu’il fallait plusieurs minutes pour générer son document, cela pouvait survenir plus d’une fois par jour.

En conclusion, privilégier un éditeur de code plus générique et plutôt orienté vers le développement logiciel n’est pas une mauvaise solution quand il s’agit de préparer une thèse en LaTeX, et je le recommande à quiconque voulant se lancer dans pareil projet.

Pas de Git : une erreur ?

Le choix technique que je regrette toutefois est celui de ne pas avoir utilisé Git.

Je n’ai pas insisté, parce que je pensais qu’elle allait de toute façon écrire sa thèse seule et je ne voulais pas introduire trop d’outils nouveaux en même temps.

Mais en raisonnant ainsi, j’ai oublié les personnes qui relisent le texte à la recherche de fautes : son professeur, ses parents… Et vers la fin, j’intervenais également sur la mise en forme, car c’était plus simple si je m’en chargeais.

En somme, nous étions deux à toucher directement au code LaTeX. Même si j’avais réussi à isoler toutes les commandes portant sur la mise en forme dans un fichier .sty qu’elle pouvait importer avec un simple \usepackage, certaines modifications nécessitaient tout de même des modifications dans le corps du document. Par ailleurs, je trouvais parfois des coquilles que personne n’avait relevé et que je voulais corriger sur-le-champ. Dans ces cas-là, il est important de se synchroniser.

Toute thèse est donc, qu’on le veuille ou non, un travail à plusieurs et c’est pourquoi il est important de traiter le texte de la thèse comme un projet collaboratif.

Git apporte aussi la faculté d’avoir un historique de son travail. Ce qui est très utile pour suivre son avancement, mais aussi pour pouvoir revenir en arrière en cas de besoin. C’est un filet de sécurité que j’apprécie beaucoup sur mes projets personnels de programmation.

Enfin, Git apporte une sauvegarde hors site « gratuite », car il est très facile d’héberger son dépôt maître sur une machine distante.

De fait, pendant les dernières phases où j’intervenais sur la mise en forme, j’avais mon dépôt Git local qui me servait de bac à sable. La branche master était celle dans laquelle j’importais son travail, et d’où partaient mes branches qui représentaient mes contributions. Après une nouvelle importation dans la branche master, j’utilisais git rebase sur toutes mes autres branches pour actualiser mon travail avec le sien ; mais dans l’autre sens, un simple git merge de ma branche dans master suffisait.

Tant pis, donc, si on n’a intégré Git que très tardivement dans ce travail. Les quelques dernières retouches ont certes été source de crispation, mais globalement, Git n’a été vraiment utile qu’à partir du moment où je modifiais moi aussi le code LaTeX de sa thèse. Et Nausicaa n’aurait peut-être pas vu l’intérêt de committer régulièrement son travail tant qu’elle travaillait toute seule dessus.

Documentclass : memoir, largement supérieur à book

Un choix technique qui s’avérait être mauvais, c’était celui d’avoir commencé à rédiger quasiment toute la thèse sous la \documentclass{book}. C’est une documentclass de base qui fait bien le travail, jusqu’à ce qu’on ait besoin d’apporter des modifications importantes sur la mise en forme, comme :

  • remplacer la page de garde par défaut par une autre, personnalisée, et utilisant des champs de métadonnées personnalisées ;
  • modifier l’apparence des titres des parties, chapitres et sections ;
  • modifier l’apparence des parties, chapitres et sections dans le sommaire et la table de matière ;
  • prévoir en début de thèse un sommaire qui s’arrête aux chapitres, en plus d’une table des matières détaillée en fin de thèse ;
  • modifier les en-têtes et pieds de page…

Pour cela, la documentclass memoir est beaucoup plus adaptée : ses possibilités de personnalisation sont à la fois puissantes et plus faciles d’accès (comparé au fait de redéfinir des commandes LaTeX de base soi-même, en tout cas) et on sent vraiment que la classe a été conçue pour des projets de grande envergure comme… des thèses.

Une chose à laquelle il faut faire particulièrement attention, ce sont les conflits avec les autres packages LaTeX, comme sectsty. Ces packages altèrent la mise en forme du document en redéfinissant des commandes internes (comme \part, \section, etc.), en supposant qu’on part d’une documentclass de base, comme book. Il ne faut surtout pas les charger avec memoir, sinon ça ne marchera pas ! À la place, il est indispensable de privilégier les fonctions de personnalisation intégrées à memoir, même si elles sont parfois un peu plus guindées. La plupart des astuces de mise en forme qu’on peut trouver sur StackOverflow ne s’appliquent plus à partir du moment où on substitue memoir à book, mais le manuel est plutôt complet.

La migration de book vers memoir n’a pas eu trop de répercussions, mais c’est une décision que j’avais prise tardivement, alors que j’avais déjà mis en place de nombreuses bidouilles intéressant la mise en forme de sa thèse. C’est donc un travail que j’ai dû reprendre en partie.

Malgré tout, si c’était à refaire, je préconise d’utiliser la classe « memoir » dès le début du projet, sans aucune hésitation.

La question de la correction orthographique

Il n’y a rien de plus désagréable que de publier un texte, de lire la forme publiée papier et de trouver des coquilles qu’on a ratées.

La question du correcteur orthographique finit donc inévitablement par se poser. Que ce soit pour un article de 12 pages ou une thèse de 600 pages, c’est un allié indispensable qui permet de rattraper des coquilles que même des relecteurs en chair et en os auraient pu rater.

Cependant, il n’existe à ma connaissance aucune solution commerciale (comme Antidote) qui soit conçu pour fonctionner directement sur le code LaTeX.

On se retrouve donc avec deux possibilités :

  • utiliser le correcteur orthographique intégré à son éditeur de texte, pourvu que la fonction existe et qu’un dictionnaire français soit disponible ;
  • ou lancer la correction orthographique sur le PDF final, ce qui nécessite cependant quelques bidouilles pour que ce soit efficace.

Dans notre cas, j’ai relu le code LaTeX sous Emacs avec flyspell-mode, ce qui m’a permis de rattraper pas mal d’erreurs. Ce mode utilise ispell, ce qui suffit à mon avis largement. Nous ne ressentions pas le besoin d’un correcteur grammatical, même si un tel correcteur peut trouver encore plus de coquilles (des fautes d’accord, par exemple).

La relecture est donc une affaire de machines et d’hommes : une machine ne s’ennuie jamais et repèrera sans faillir la moindre petite inversion de lettres noyée dans un océan de centaines de milliers de mots (comme « cyclimse » au lieu de « cyclisme »), mais un relecteur en chair et en os est capable d’identifier d’autres problèmes que juste ceux de pure forme.

Le moment du rendu

Le rendu de la thèse à la Sorbonne est électronique : il faut soumettre à la fois un fichier PDF qui respecte un certain nombre de contraintes, mais aussi les fichiers « source ».

Entre autres, le PDF doit utiliser une première et une quatrième de couverture imposées par la faculté de lettres. Le gabarit est bien évidemment fourni… sous format Word (sinon, ce ne serait pas drôle). Et tout le travail que j’avais fait pour redéfinir la commande \maketitle dans le code source de sa thèse était bon pour la poubelle.

Heureusement, quelques coups de LibreOffice pour remplir le modèle, puis une petite commande pdftk plus tard (qu’elle a trouvée elle-même alors qu’elle abhorre généralement la ligne de commande !) et le PDF de la thèse était prêt.

En revanche, du côté du format source, il faut dire que la dame du bureau de dépôt des thèses ne s’attendait pas du tout à un répertoire rempli d’images au format PDF (ben oui, c’est un format de dessin vectoriel comme un autre après tout). Et elle ne savait encore moins quoi faire de ces mystérieux fichiers .tex. Il est clair qu’il n’y a que peu d’informaticiens à la Sorbonne.

Conclusion : « La présentation du volume est soignée »

Parmi les rapports préliminaires qu’elle a reçues avant de soutenir sa thèse, une des membres du jury a écrit que « la présentation du volume est soignée ».

Et je dois dire que LaTeX permet, en effet, d’obtenir d’emblée un très bon résultat du point de vue visuel. Un PDF généré par LaTeX dégage une aura bien particulière, que Word ou LibreOffice seraient incapables d’égaler (ce que décrit bien ce billet de blog). Les algorithmes de calcul de la meilleure mise en page d’un paragraphe, de césure des mots, de placement d’éléments « flottants » comme les tables et les figures et d’autres encore, utilisent comme critère d’optimisation de nombreux petits détails subtils qui participent à créer cette aura. En typographie tout particulièrement, le diable est en effet dans les détails.

Chaque jour, quand je rentrais du travail et que je la voyais travailler sur sa thèse, je prenais toujours un peu de temps pour admirer la prévisualisation PDF et son apparence visuelle suffisait pour me donner envie de le lire, même si c’était loin d’être fini. Sa thèse est comme une cathédrale qu’on admire alors même qu’elle est loin d’être terminée.

Le seul bémol, c’est que personnaliser l’aspect visuel de son document pour lui donner une touche personnelle demande beaucoup de travail. Pour cela, j’ai lu enter autres le TeXbook de Donald Knuth, le mode d’emploi (et le code) du documentclass « book » avec, en guise de référence, le code source annoté du cœur de LaTeX. Heureusement, la documentclass memoir m’a épargné pas mal de tracas.

Maintenant que la thèse a été soutenue, il ne reste plus qu’une chose à faire, et pas des moindres : la publier.

pass : un gestionnaire de mots de passe simple et efficace

 x0r   0
linux pass gpg sécurité password

De nos jours, l’explosion du nombre de comptes que l’on doit créer et maintenir auprès de services en ligne constitue en effet autant de mots de passe qu’il faut inventer et retenir. Entre le compte mail, souvent plusieurs comptes chez des sites marchands en ligne, les démarches administratives (comme les impôts ou le compte personnel de formation, dont j’avais cassé le site Web dans le passé) voire les mots de passe dont on peut être amené à se souvenir au travail, on finit rapidement à plusieurs dizaines de mots de passe à retenir. Si pour bien faire les choses, on vous prie de choisir des mots de passe à la fois forts (longs et puisant dans les lettres, les chiffres et les symboles) et uniques, la gymnastique mentale devient vite fastidieuse.

Il y a beaucoup de mauvaises méthodes pour gérer plusieurs dizaines de mots de passe forts dans sa tête : on est vite tenté d’utiliser le même mot de passe sur au moins deux services différents. Guère mieux est le fait de construire ses mots de passe à partir d’un préfixe et d’un suffixe identiques tout en dérivant le reste du mot de passe du nom du service.

La dernière méthode consiste à mettre en œuvre un gestionnaire de mots de passe : un utilitaire qui retient chaque mot de passe à la place de l’utilisateur en les stockant dans un stockage chiffré, déverrouillable uniquement à l’aide d’un mot de passe maître.

Je savais depuis un moment qu’il me fallait un gestionnaire de mots de passe, moi aussi, simplement pour me prémunir des risques que constitueraient la compromission de la base de données de mots de passe d’un des nombreux services Web chez qui j’ai un compte. J’ai pris le temps d’étudier de nombreuses alternatives sans en trouver une qui me plaise.

Depuis quelques mois, j’utilise un petit gestionnaire de mots de passe qui s’appelle pass et que j’aime beaucoup. Il est gratuit et libre et va à l’essentiel de ce qu’est un gestionnaire de mots de passe : un système de stockage de secrets dans une base de données chiffrée. Je vous propose un petit tour d’horizon de cet outil et de ses possibilités.

Présentation

Pass est sans doute le gestionnaire de mots de passe le plus simple que j’ai pu voir : il s’agit en effet d’un script shell d’environ sept cents lignes. Les mots de passe en eux-mêmes sont stockés dans des fichiers texte, chiffrés avec GPG avant d’être placés dans une arborescence arbitraire de fichiers et de répertoires, ce qui permet de les sauvegarder sans peine et de les partager entre plusieurs machines avec Git par exemple. L’outil est par ailleurs extensible et bénéficie déjà d’intégrations avec les navigateurs Web les plus répandus.

Premiers pas

Installation

Votre système d’exploitation *nix fournit vraisemblablement déjà un paquet. Il suffit donc d’installer le paquet pass (ou password-store sous FreeBSD) pour installer le logiciel en lui-même.

Initialisation du stockage des mots de passe

Cependant, une fois installé, le logiciel n’est pas encore prêt à l’emploi. Il faut d’abord initialiser la base de données de mots de passe. Pour cela, nous allons d’abord créer une clef GPG dédiée au chiffrement de mots de passe et qu’on gardera distincte des autres. De manière générale, c’est toujours une bonne pratique d’utiliser des clefs distinctes pour des usages distincts.

Pour cela, un simple gpg --full-generate-key suffit dans un terminal. Pour mon propre usage, je n’ai pas donné de nom ni d’adresse e-mail, mais seulement un commentaire indiquant que la clef sert uniquement de clef de chiffrement pour des mots de passe.

Prenez note de l’identifiant de la clef nouvellement créée, puis initialisez Pass avec pass --init <ID de clef GPG>.

La dernière étape, facultative, est d’initialiser le dépôt Git dans la base de données de mots de passe. Pour cela, pass git init fera l’affaire. Dans la plupart des cas, vous voudrez alors pousser votre base de mots de passe sur une machine distante ; il faudra alors renseigner le distant avec une commande de la forme pass git remote add origin ssh://utilisateur@example.com/home/utilisateur/.pass.git.

Générer un nouveau mot de passe aléatoire

Lorsqu’on crée un nouveau compte ou qu’on change pour la première fois le mot de passe d’un service, la commande pass generate fait tout le travail :

pass generate Sites\ Web/Social/Diaspora

Par défaut, pass affiche le mot de passe qu’il a généré sur le terminal. Veillez donc à ce que personne ne regarde par-dessus votre épaule au moment où vous lancez cette commande ! Alternativement, pass peut aussi copier le nouveau mot de passe dans le presse-papiers si vous donnez l’option =-c= ; vous avez alors 45 secondes pour le coller dans la page Web avant qu’il soit supprimé du presse-papiers. À ce stade, le mot de passe est stocké dans la base de données et si vous utilisez Git, un commit aura été fait.

Quand ça ne marche pas

Pass génère par défaut des mots de passe de 24 caractères en puisant dans les 94 caractères imprimables du jeu de caractères ASCII. Il arrive parfois que certains sites aient du mal avec les mots de passe contenant certains caractères que les développeurs n’ont pas prévu dans leur code ; il arrive aussi que des sites rejettent des mots de passe trop longs. Dans les deux cas, ce sont des bugs et dans le second cas, cela peut aussi suggérer que le site stocke en fait ses mots de passe en mépris de l’état de l’art (en clair, par exemple).

Dans ces cas, pass generate accepte l’option -n pour générer un mot de passe sans symboles et il est possible de paramétrer au cas par cas la longueur du mot de passe à générer.

Retrouver un mot de passe préalablement stocké

Pour retrouver le mot de passe qu’on vient de stocker et le copier dans le presse-papiers, taper pass -c <nom du compte>. Après avoir tapé le mot de passe de la clef de chiffrement, le mot de passe en question est déchiffré et copié dans le presse-papiers (puis effacé du presse-papiers après 45 secondes).

Cette manipulation est un peu fastidieuse si on n’a pas déjà un terminal ouvert à côté de son navigateur. Heureusement, des extensions pour Firefox et Chrome existent. Puisque j’utilise Firefox, je parlerai seulement de Firefox ici, mais il me semble que l’intégration avec Chrome fonctionne de la même manière.

Intégration avec Firefox

L’intégration Firefox de pass nécessite l’installation de deux composants : passff-host d’une part, qui est un petit « wrapper » autour de pass et passff d’autre part, l’extension Firefox en lui-même.

En installant ces deux composants, le navigateur remplit automatiquement les identifiants et mots de passe des sites Web renseignés dans la base de données, comme la majorité des gestionnaires de mots de passe.

Installation de l’application hôte

On peut installer l’application hôte de plusieurs façons. Ils proposent de télécharger un script shell depuis la rubrique « /Releases/ » de la page GitHub et l’exécuter. Ce script télécharge et installe l’application hôte.

Une autre alternative est de télécharger tous les fichiers localement puis d’exécuter le même script shell avec l’option --local.

Dans tous les cas, les droits root ne sont pas nécessaires pour installer l’application hôte.

Installation de l’extension Firefox

Pour l’extension Firefox, il suffit de se rendre sur la page de l’extension passff sur addons.mozilla.org et de suivre la même procédure que pour installer n’importe quelle autre extension Firefox.

Format des fichiers de mot de passe

Pour que le remplissage automatique fonctionne, il faut modifier ses fichiers de mot de passe existants pour y ajouter quelques métadonnées. Pour cela, taper :

pass edit <nom_du_service>

Ceci déchiffre et ouvre le fichier de mot de passe dans un éditeur de texte, avec le mot de passe en première ligne. Modifier ensuite le fichier pour qu’il ait la forme suivante :

<mot de passe>
URL: https://*.example.com/* (à adapter selon les URL des pages de connexion)
Username: votre_identifiant

Sauvegardez et quittez. Si vous vous rendez sur la page de connexion du service, le formulaire n’est pas automatiquement rempli mais si vous cliquez sur l’icône en forme de « p » dans la barre d’outils de Firefox, passff vous proposera de remplir le formulaire avec les informations que vous avez stockées dans pass.

Remplissage automatique des champs

Par défaut, passff ne remplit pas automatiquement les champs des formulaires de connexion. Si vous voulez activer ce comportement, il vous faut aller dans les préférences de l’extension.

Notez cependant que vous n’êtes jamais complètement à l’abri du risque de fuite de vos mots de passe si vous activez cette fonction : certaines attaques visant des gestionnaires de mots de passe exploitent justement la fonction de remplissage et d’envoi automatique d’identifiants. Ce genre de fonctions est donc à activer à vos risques et périls.

Conclusion

Je n’ai donné qu’un aperçu très superficiel des fonctionnalités de pass ; néanmoins, l’outil est suffisamment souple pour permettre des usages avancés que je ne détaillerai pas dans ce billet.

En tout cas, mon passage à un gestionnaire de mots de passe apporte un confort certain. Je profite la plupart des temps de l’occasion de me connecter à un service que je n’ai pas encore converti à pass pour le faire.

L’usage d’un gestionnaire de mots de passe peut pousser certains sites Web dans ses retranchements. Hormis les problèmes que j’ai détaillés ci-dessus, j’ai aussi eu droit aux sites qui m’interdisaient le copier-coller dans le champ « Confirmer le mot de passe ». D’autres sites interdisent carrément le copier-coller d’identifiants sur leurs pages de connexion (une très mauvaise idée). Néanmoins, l’idée de pouvoir utiliser des mots de passe extrêmement complexes sans avoir besoin de s’en souvenir me plaît beaucoup et, dans le cas de pass, il me semble tout à fait faisable de sécuriser davantage ses secrets en investissant dans une YubiKey ou une authentification par carte à puce.

Utiliser une imprimante Canon Pixma TR8550 sous Linux

 x0r   5
linux canon retour expérience pixma imprimante scanner

Suite à la mort inopinée de ma précédente imprimante, une HP OfficeJet 6700 Premium qui m’avait inspiré, il y a longtemps, à écrire un billet de blog coup de gueule à propos des pilotes d’imprimante, j’ai été obligé de racheter en catastrophe une nouvelle imprimante multifonction.

Canon Pixma TR8550
Mon imprimante Canon Pixma TR8550.

J’ai jeté mon dévolu sur une Canon Pixma TR8550, qui est une imprimante plutôt compacte et adaptée à mon usage : des impressions occasionnelles de documents, mais surtout beaucoup de scans.

Puisque faire fonctionner cette machine sous Linux était un peu plus compliqué que prévu, je vous propose donc ce petit retour d’expérience, dans lequel je décris ce qu’il a fallu que je fasse pour profiter pleinement de cette imprimante sous Gentoo.

Installer le pilote d’impression, cnijfilter

Il s’agit malheureusement d’un de ces appareils qui nécessite la compilation et l’installation, depuis les sources, de son pilote, qui est de plus fourni avec une collection de bibliothèques sous forme de « blob » binaire. Bref, donc pour ceux qui abhorrent l’idée de faire tourner des logiciels propriétaires sur leur poste libre, cette imprimante n’est pas pour vous.

Sous Gentoo, le pilote est heureusement déjà disponible dans l’arbre Portage. Pour l’installer, il suffit en théorie de taper :

# emerge cnijfilter2

Sauf qu’au jour où j’écris ces lignes, la version de cnijfilter2 dans l’arbre Portage est trop ancienne : il faut la version 5.50 alors que Portage propose la version 5.40. Cependant, un ebuild à jour a déjà été soumis à Gentoo, donc il suffit en théorie de le télécharger et l’installer :

# mkdir -p /usr/local/portage/net-print
# cd /usr/local/portage/net-print
# cp -r /usr/portage/net-print/cnijfilter2 .
# cd cnijfilter2

Placez ensuite le fichier cnijfilter2-5.50.ebuild que vous avez préalablement téléchargé dans /usr/portage/net-print/cnijfilter2. Puis tapez la commande :

# ebuild cnijfilter2-5.50.ebuild manifest

Ajoutez dans votre /etc/portage/package.keywords la ligne suivante :

net-print/cnijfilter2

Enfin, ajoutez /usr/local/portage à votre PORTDIR_OVERLAY si ce n’est pas déjà le cas. Vous pourrez alors installer le pilote avec :

# emerge cnijfilter2

Ajout de l’imprimante dans CUPS

Pour ajouter l’imprimante dans CUPS, c’est heureusement plus facile. Il suffit de visiter l’URL http://localhost:631. Dans l’onglet « Administration », cliquez sur « Add printer » ; si l’imprimante est allumée, elle devrait alors immédiatement apparaître dans la section « Discovered network printers ».

Lorsque CUPS demande le pilote à utiliser, il faudra choisir le pilote « Canon TR8500 series Ver.5.50 » (ils n’ont pas fait de fichier PPD pour le modèle exact, ce qui est étonnant). Le reste est suffisamment simple et pour ma part, la page de test est sortie du premier coup.

Pour scanner, ça se complique

En revanche, ce qui m’a donné de loin le plus de fil à retordre était la partie scanner. Pour l’utiliser, Il faut passer par l’utilitaire propre à Canon, baptisée « ScanGear MP » ; je n’ai pas réussi à faire fonctionner SANE.

La principale raison est qu’un bug s’est glissé dans ScanGear. Après avoir pas mal lutté pour l’installer sur ma machine, j’ai voulu scanner une page de test. Las ! l’outil segfaulte juste après avoir sélectionné l’emplacement lequel écrire le PDF.

Il s’avérait donc que c’était tout simplement la faute d’un pointeur non initialisé à NULL avant sa première utilisation. Il m’a fallu corriger ce petit bug avant que ça marche.

Pour le reste, j’ai écrit un ebuild, que j’ai soumis à Gentoo. Il m’a fallu environ une soirée pour le mettre au point, et une petite heure de plus pour le mettre au propre. Mais un jour, peut-être, vous pourrez installer l’utilitaire de scan avec la commande emerge scangearmp2.

Pour le reste, rien de vraiment folichon : l’outil se lance avec la commande scangearmp2, propose quelques réglages élémentaires et un bouton pour scanner. La résolution du scan est fixée ; à combien, je l’ignore, mais elle est égale ou supérieure à 300 ppp, ce qui suffit largement pour mon utilisation.

Capture d’écran de ScanGear MP
La fenêtre principale de ScanGear MP.

Conclusion

Je peux m’estimer heureux que le bug de ScanGear se résumait à un simple pointeur non initialisé, parce qu’en activant les avertissements de compilation (-Wall), le résultat fait un peu peur.

Quoi qu’il en soit, je me suis rapproché du service client de Canon, et je leur ai transmis le patch en leur expliquant le problème que j’ai corrigé. J’espère donc que ce correctif finisse par être intégré officiellement.

Bien que je trouve légèrement frustrante la nécessité d’installer des logiciels propriétaires de Canon, je saurai m’en accommoder si cette imprimante s’avère être fiable. On verra bien dans combien de temps il me faudra la changer, mais en attendant, croisons les doigts.