Je vais de nouveau tenter d'écrire un ou plusieurs billets pas trop interminables. On va voir comment ça va marcher.
Ce que je veux dire ici va recouvrir en partie ce que je disais déjà dans ce billet récent mais concerne un aspect un peu différent : la difficulté à compiler des programmes sous Linux. Et ce n'est pas juste que ça devient difficile, c'est aussi que plus grand-monde ne le fait, et les deux aspects forment un cercle vicieux.
👉︎ Quelques explications
terminologiques pour les personnes pas trop familières de
l'informatique : Quand on [= des humains] écrit un programme, la forme
textuelle du programme (ou package
) sur laquelle
on travaille est appelée le code source, ou de façon un peu
abusée, le source
(notez le genre masculin). La forme que
l'ordinateur est capable d'exécuter est appelée l'exécutable
binaire, ou de façon un peu abusée, le binaire
. Comme le
binaire est illisible et non éditable en pratique par un humain, et
qu'il dépend des détails de l'ordinateur sur lequel on va le faire
tourner (type de processeur, système d'exploitation, etc.), on préfère
souvent distribuer le source et refabriquer le binaire au besoin.
L'opération par laquelle on passe du source au binaire est appelée
la compilation
(bon, c'est simplifié parce qu'il peut y avoir
d'autres opérations qui vont avec, par exemple de préparer des
fichiers de données annexes, mais c'est l'idée). Conceptuellement, ce
n'est pas compliqué, on applique un programme appelé compilateur sur
le source et il fabrique le binaire (adapté au processeur et à
l'OS souhaités). En pratique, le diable est dans les
détails, il y a énormément de bouts de source à compiler dans un ordre
bien précis, souvent avec des dépendances compliquées, il faut donner
des options très précises au compilateur, et il existe toutes sortes
de mécanismes différents servant à lancer la compilation comme il
faut.
À titre d'exemple, je compile mes propres Firefox[#] à partir du source. Je ne connais absolument personne d'autre qui fasse ça. Pourtant, je fréquente pas mal de geeks, mais je n'ai jamais rencontré qui que ce soit d'autre que moi qui compile Firefox (régulièrement, ou même de temps en temps pour essayer) et qui ne soit pas dans — ou facilement assimilable à — l'une des deux catégories évidentes : ⓐ développeur pour Mozilla, ou bien ⓑ mainteneur d'une distribution Linux. Absolument personne. Je sais parce que j'ai souvent fait des appels à l'aide suite à des problèmes de compilation de Firefox, et personne ne répond jamais. Tout le monde télécharge simplement son Firefox sous forme de binaire sur le site de Mozilla, ou utilise celui de sa distribution.
[#] La principale raison
pour laquelle je le fais est qu'il y
a un bug
insupportable dans Firefox depuis plus de 20 ans(!) qui fait qu'il
transforme des espaces insécables (U+00A0
NO-BREAK SPACE) en espaces normales
(U+0020 SPACE) lors du copier-coller
dans de nombreuses circonstances. Comme je ne veux pas que ce billet
devienne interminable, je ne donne pas plus de détails,
mais voyez
ce fil Bluesky si vous voulez en savoir un peu plus sur le fait
que ce bug a été partiellement mais non complètement corrigé, et
pourquoi ils ne veulent pas le corriger complètement. Bref, j'ai un
patch très facile qui le corrige en grande partie (mais pas
complètement non plus) et je tiens à l'appliquer.
Je ne veux pas trop jouer au vieux con sur l'air de c'était
mieux âââvant
, mais j'ai connu une époque où c'était assez normal
de compiler beaucoup de programmes qu'on utilisait. Les raisons
pouvaient varier (programme pas packagé par la distribution, souhait
d'appliquer un patch ou de changer les options de compilation ou de
configuration ou les d'utiliser des bibliothèques différentes, ou
d'avoir une version différente, ou simple question de principe), en
tout cas, c'était courant.
Et ce n'est pas juste que c'était courant : c'est le principe
d'utiliser des logiciels libres, ou open source,
que ce soit possible. C'est la liberté la plus basique derrière le
terme de logiciel libre
, c'est la base de la notion
d'open source, et le problème fondamental avec
les libertés qu'on n'utilise pas, c'est qu'elles finissent toujours
par s'éroder.
Je ne dis pas que c'était terriblement facile. Quand j'ai
commencé à utiliser des Unix, c'était vraiment assez chaotique,
généralement il fallait éditer des fichiers d'options de compilation
pour dire à quoi ressemblait le système pour lequel on voulait
compiler (et parfois on n'avait aucune idée de la réponse à des
questions du style les gestionnaires de signaux se comportent-ils
façon BSD ou façon System V ?
). Puis est venu un jeu
d'outils appelé les GNU
autotools
qui fabriquent un script appelé configure
qui détecte tout seul plein de choses sur le système au lieu de
demander à l'opérateur humain de répondre à toutes ces questions :
très commode quand ça marchait, mais souvent ça ne marchait pas et on
ne savait pas comment réparer le
problème[#2]. Néanmoins, ils
avaient l'avantage d'être assez standards, donc on savait à quoi
s'attendre et comment s'en servir.
[#2] Ceci est un phénomène récurrent et courant en informatique : plus quelque chose est automatisé, plus c'est commode quand ça marche, mais compliqué de réparer les choses quand quelque chose ne va pas. Il y a certainement des moyens de réduire la tension entre les deux (par exemple fournir des outils capables de décomposer les étapes, montrer ce qu'ils font à chaque étape, proposer des moyens de modifier le comportement à chaque niveau, etc.), mais ils ne sont pas assez mis en œuvre.
A contrario, distribuer des programmes sous forme binaire était terriblement difficile, quasi impossible, il y a 25–30 ans : Linux était quasiment incompatible avec Linux, chaque distribution avait ses propres idiosyncrasies, rendant la compilation quasiment obligatoire. Soit votre distribution se chargeait de vous donner exactement le bon binaire pour vous, soit il fallait le produire par vos propres moyens à partir du source.
Il me semble qu'il y a eu plusieurs évolutions. Distribuer les binaires est devenu plus facile : les distributions Linux ont fait des efforts pour se rendre au moins minimalement compatibles entre elles, les Unix autres que Linux (et éventuellement les *BSD) ont quasi disparu, l'espace disque et le temps de compilation sont plus abondants ce qui permet plus facilement aux auteurs d'un projet de fournir plein de binaires précompilés ; et aussi, divers systèmes sont apparus (Snap, Flatpak, Docker, etc.), que je trouve absolument abominables mais c'est un autre débat, pour permettre de distribuer un programme en même temps que toutes ses dépendances sous une forme qui est censée « juste marcher ». Peut-être aussi que plus de programmes sont fournis par les distributions.
Toujours est-il que ces évolutions ont diminué le besoin de recompiler à partir du source. Et je crois que les gens qui ne sont ni ⓐ développeurs du projet Machintruc ni ⓑ mainteneurs de celui-ci pour le compte d'une distribution, compilent de plus en plus rarement.
Le principal projet qui me semble faire encore exception, c'est le noyau Linux lui-même. Parce qu'il est particulièrement facile à compiler vu qu'il n'a essentiellement pas de dépendances, et parce que le gain est important vu la myriade d'options qu'on peut régler en le compilant, ou de patchs qu'on peut vouloir sélectionner, si bien qu'il est difficile pour les distributions de fournir une version compilée qui convienne à tout le monde. Mais même le noyau, je pense que beaucoup moins de gens le compilent maintenant qu'il y a 25–30 ans ; et l'apparition de code Rust dedans ne va certainement pas simplifier les choses.
Évidemment, il y a des nuances selon les distributions Linux : Gentoo, par exemple, part du principe qu'on compile (quasiment) tout localement. Mais ce n'est pas la compilation au sens dont je parle ici : je parle de recompiler la version upstream, celle qui est publiée par les auteurs du programme, pas un package source créé par les mainteneurs de la distribution (et qui est garanti fonctionner parce que tout a été fait pour, mais qui n'est pas fondamentalement différent d'un binaire quand il s'agit de bidouiller dans les options). Idem pour Nix[#3], qui utilise l'approche consistant à tout figer au bit près. Tout ça ne règle pas le problème fondamental sous-jacent : pour qu'un logiciel soit véritablement open source, il faut qu'on puisse lire, éditer et recompiler son source (celui distribué par les auteurs du projet, pas une version spéciale adaptée pour la distribution), sans que ce soit impossiblement compliqué ; et ce, même si on n'est pas développeur du projet ou mainteneur d'une distribution, et sans que la distribution ait mâché le travail pour nous.
[#3] Les fans de Nix sont insupportables à venir toujours faire la pub de leur truc : Nix n'est pas une solution au problème que les sources sont difficiles à compiler parce que les dépendances sont devenues impossiblement touffues et parfois contradictoires — Nix est un constat d'échec et une façon de contourner le problème en actant ce constat d'échec, mais qui ne règle rien au problème lui-même.
Et il me semble que plus le temps passe, plus la compilation
devient difficile. Ça peut être lié à la multiplicité des
dépendances, ou au fait qu'elles soient extrêmement pointilleuses
(je veux utiliser la version 1.729.42b(8)-deadbeef de la libfoobar
et pas une autre
). Ça peut être lié aux langages utilisés. Ça
peut être simplement le fait que comme de moins en moins de
non-développeurs compilent, les auteurs font de moins en moins
d'efforts[#4] (les mainteneurs
pour les distributions vont de toute façon tout refaire à leur sauce).
Ou peut-être que c'est simplement lié à la démocratisation de Linux et
du fait que les utilisateurs n'aient pas envie de compiler des choses
(mais ceci ne peut pas vraiment expliquer la
diminution absolue du nombre de gens qui le font, seulement
une diminution relative).
[#4] À l'inverse, on
vous pousse à récupérer un binaire, et tout est fait pour rendre ça
facile : on vous dit souvent carrément de faire curl
someinstallscript | sh pour, en gros, aller chercher un script
en ligne et l'exécuter directement (ce qui est d'ailleurs un cauchemar
absolu question sécurité). En tout cas, autrefois, le
lien download
d'un projet Linux typique pointait
vers le source, maintenant il pointe vers le binaire (et pour le
source on vous renvoie typiquement juste à une page GitHub sans
explications).
La difficulté peut prendre diverses formes. Parfois c'est
simplement une absence d'explications sur comment compiler le projet :
il est difficile d'y voir là autre chose qu'une attitude du
style les développeurs savent comment faire, les mainteneurs des
distributions feront leur propre sauce, et les autres n'ont qu'à
récupérer un binaire
. (Ou si ce n'est pas un manque
d'explications sur comment compiler, ça peut être sur la façon
d'installer le(s) binaire(s) une fois compilé(s), ou même sur
l'endroit où ils se trouvent à la fin de la compilation.) Parfois
c'est une absence d'explications sur l'outil
utilisé[#5]. Le bon vieux
système du ./configure --prefix=/some/where
&& make && make install avait toutes sortes de
problèmes, mais au moins on savait quoi faire parce qu'il était
standard au point d'être quasi universel.
[#5] Par exemple, les
projets Rust utilisent cargo : fort bien, mais il faut se
rappeler que la personne qui cherche à compiler le projet ne connaît
peut-être rien de Rust (ou peut-être juste assez pour changer, disons,
un message d'erreur ou un comportement trivial), et n'a peut-être
aucune idée de comment utiliser cargo ni ne veut
apprendre. Pour un outil comme make qui peut servir à
n'importe quel langage, il est raisonnable de demander que celui qui
veut compiler apprenne à s'en servir, mais si l'outil est spécifique à
un langage, ce n'est pas raisonnable vu le nombre de langages de
programmation différents qui existent. (Et on ne peut pas simplement
renvoyer à la doc, qui est généralement beaucoup trop longue, trop
générale, et trop orientée pour les gens connaissant déjà le langage
et ses conventions, pour pouvoir servir aux gens qui veulent juste
compiler une fois un projet utilisant cet outil. Ou alors l'outil
doit prévoir une doc spécifique pour ce cas.)
Parfois c'est une difficulté cachée sous une façade en trompe
l'œil on a fourni un script qui permet de tout compiler
automagiquement
(pour la compilation de Firefox, ce script
s'appelle mach), ce qui semble effectivement facile mais
se transforme en cauchemar dès que quelque chose ne va pas exactement
comme prévu (cf. ma note #2
ci-dessus) ou dès qu'on sort du périmètre exact du script magique qui
fait tout.
Certains sont d'ailleurs tellement pinailleurs qu'ils commencent
par télécharger la version exacte du compilateur qui va faire marcher
la compilation (Firefox est de ce genre : il veut une version
tellement précise de CLang et Rust et compagnie que le
script magique qui le compile commence par télécharger les binaires de
tout ça). On se demande un peu quel est l'intérêt de compiler si en
fait la compilation
consiste à aller chercher d'abord les
binaires pour le compilateur qui est le seul à pouvoir servir ! Le
source est ce qui est censé pouvoir permettre de reproduire l'outil
qu'on compile ab ovo à partir d'outils standards,
pas à partir d'une version unique du compilateur que vous ne pouvez
pas reproduire elle-même.
Un problème supplémentaire est que ces outils compliqués ont
tendance à devenir de moins en moins reproductibles : ils vont stocker
des choses dans votre répertoire personnel
($HOME)[#6], soit
des bouts de code téléchargés ou déjà compilés ou carrément installés
localement, soit un état global (options de configuration ou de
compilation, variables diverses), et comme on ne sait pas où et
comment ces choses sont stockées ni ce qui peut l'être, on perd
l'aspect reproductible d'une compilation. Là aussi, la documentation
peut être particulièrement opaque pour qui n'a pas envie d'apprendre à
se servir en détail de l'outil, juste de compiler un projet bien
précis.
[#6] La pollution
du $HOME est une des choses qui m'énervent
particulièrement : autrefois, ça ne se faisait jamais, mais maintenant
tout le monde semble trouver normal de faire ses besoins malodorants
dans un sous-répertoire de $HOME sans qu'il y ait un
avertissement préalable. Comme le mien est distribué entre plusieurs
machines et fait l'objet de sauvegardes abondantes, l'espace dedans
est particulièrement cher : je n'ai pas envie que la moindre
compilation le remplisse de giga-octets de données partiellement
compilées. Si je lance la compilation
dans /usr/local/src/somepackage-0.42 j'entends bien qu'il
se serve de ce répertoire et de ce répertoire seulement pour
toute écriture. Quand j'ai un doute, je compile sous le nom d'un
utilisateur qui n'a pas le droit d'écrire dans son $HOME,
ce qui provoque une erreur s'il cherche à le faire : mais si ça
arrive, ça ne me dit quand même pas comment remédier au problème.
Toujours est-il que Linux évolue de plus en plus dans la direction
d'Android[#7]. Il y a bien
quelques logiciels open source dans les
applications Android, mais essayer de fabriquer un .apk
binaire à partir du source est une tâche incroyablement
difficile, et je ne parle pas de recompiler le système Android
lui-même (en gros il vous faudra une machine dédiée à ça, avec
exactement la bonne version de tous les outils). Et de toute façon,
même si vous y arrivez, vous ne pouvez même pas vraiment vous en
servir, parce que vous ne pouvez pas signer l'application avec la clé
des distributeurs, donc le système Android, sous le prétexte
de sécurité
(bidon), ne vous laissera pas installer la version
que vous aurez compilée à moins d'effacer totalement la version
antérieure (et donc de perdre toutes vos données). Bref, tout est
fait pour que vous n'ayez aucune liberté dans l'affaire
(cf. cet autre billet).
[#7] Oui, Android est un Linux en interne, mais il n'y ressemble pas du tout, et il n'est pas du tout fait pour vous laisser bidouiller avec, cf. ce que j'écrivais il y a déjà 11 ans.
Je propose d'utiliser le terme clopen source
(clopen
est un mot-valise
entre closed
et open
, souvent
utilisé en topologie) pour parler de ces projets qui sont
théoriquement open source, mais en pratique faire
quelque chose du source est tellement difficile (soit parce qu'il est
difficile à compiler ou à comprendre comment compiler, soit parce
qu'il y a d'autres barrières comme les signatures Android dont je
viens de parler) que c'est presque complètement théorique.
Sur le papier, l'open source a gagné, beaucoup de projets importants ont maintenant un code source public, mais en pratique, c'est surtout le clopen source qui a gagné : vous avez accès à du code, mais c'est tellement difficile d'en faire quoi que ce soit que personne n'en fait rien, et en plus tout le monde s'en fout. Est-ce que ça valait la peine de se battre pour la liberté des logiciels si c'était pour en arriver là ?