Haskell · Cabal · outillage de build
Les sandboxes Cabal : ce qu’elles étaient et ce qui les a remplacées
cabal sandbox lui-même appartient désormais à l’histoire — si vous voulez juste le workflow moderne, passez directement à quoi utiliser aujourd’hui.Quand cabal sandbox est arrivé dans cabal-install 1.18 en août 2013, il a corrigé la chose la plus pénible du développement Haskell de l’époque : la base de paquets globale. Avant les sandboxes, chaque cabal install écrivait dans un store ~/.cabal partagé unique. Installez deux projets nécessitant des versions différentes de la même bibliothèque et vous obteniez le fameux « enfer des dépendances » — une base globale corrompue qui se terminait souvent par rm -rf ~/.ghc ~/.cabal et un nouveau départ.
Les sandboxes ont rendu les dépendances propres à chaque projet. Ce principe n’a jamais disparu — mais le mécanisme, oui. Voici le tableau complet, du fonctionnement des sandboxes au workflow façon nix qui les a remplacées.
Ce qu’était réellement une sandbox
Une sandbox était une base de paquets locale au projet. Vous en créiez une dans le répertoire de votre projet :
$ cd my-project
$ cabal sandbox init
Writing a default package environment file to
/home/you/my-project/cabal.sandbox.config
Creating a new sandbox at
/home/you/my-project/.cabal-sandbox À partir de là, cabal install et cabal build exécutés dans ce répertoire utilisaient .cabal-sandbox/ au lieu du store global. Deux projets pouvaient dépendre de versions conflictuelles de aeson ou text sans jamais interférer, car chacun avait sa propre base isolée.
Dépendances source locales
L’autre fonctionnalité réellement utile était add-source, qui permettait à une sandbox d’intégrer une bibliothèque directement depuis un dépôt local — inestimable quand on bricole une bibliothèque et une application ensemble :
$ cabal sandbox add-source ../my-library
$ cabal install --dependencies-only
$ cabal build Modifiez ../my-library, reconstruisez l’application, et cabal détectait le changement et recompilait la dépendance. C’était ce que Haskell avait de plus proche d’un workflow monorepo en 2013.
Pourquoi les sandboxes ont fini par être retirées
Les sandboxes résolvaient l’isolation mais laissaient deux problèmes non résolus :
- Aucun partage entre projets. Chaque sandbox recompilait le monde de zéro. Dix projets dépendant de
lenssignifiaient dix builds distincts delenset de son énorme arbre de dépendances — lent et gourmand en disque. - Aucune reproductibilité entre machines. Une sandbox capturait où vivaient les paquets, pas un plan précis et reproductible de quelles versions exactes seraient choisies. Deux développeurs exécutant les mêmes commandes à une semaine d’intervalle pouvaient quand même obtenir des builds différents.
La solution, empruntée conceptuellement à Nix, fut de rendre les builds adressés par contenu et partagés globalement : construire une combinaison paquet-version-options donnée une seule fois, la stocker sous un hash dans un store global immuable, et laisser chaque projet ayant besoin de cette combinaison exacte la réutiliser. C’est cela les « builds locaux façon nix », apparus sous le nom de new-build dans Cabal 2.0.
Quoi utiliser aujourd’hui (2026)
cabal sandbox a été déprécié durant la série Cabal 2.x et entièrement supprimé dans les versions ultérieures. Le workflow moderne par défaut du cabal-install actuel ne nécessite aucune étape d’init — l’isolation est automatique :
# In any project directory with a .cabal file:
$ cabal build # nix-style local build (v2 is the default now)
$ cabal run
$ cabal repl
$ cabal test Ce qui se passe sous le capot est exactement l’isolation par projet que promettaient les sandboxes, plus le partage qui leur manquait :
- Les artefacts de build de votre projet vont dans un répertoire local
dist-newstyle/(le successeur spirituel de.cabal-sandbox/). - Les dépendances compilées vont dans un store global immuable (
~/.cabal/store, ou sous~/.local/state/cabaldans les agencements récents), indexé par un hash du paquet, de la version, des dépendances et des options. Construisezlensune fois ; chaque projet réutilisant le même plan référence la même entrée du store. - Un fichier
cabal.projectremplacecabal.sandbox.configpour la configuration, les builds multi-paquets et le pinning.
L’équivalent moderne de add-source
Les dépendances source locales et distantes vivent désormais dans cabal.project :
# cabal.project
packages: . ../my-library
-- or pull a dependency straight from git:
source-repository-package
type: git
location: https://github.com/owner/some-lib
tag: 0a1b2c3d C’est strictement plus puissant que add-source : cela gère plusieurs paquets locaux, des pins git exacts et des builds multi-dépôts reproductibles.
Pinning de versions reproductible
Pour la reproductibilité que les sandboxes n’ont jamais offerte, générez un fichier de gel qui verrouille chaque version transitive :
$ cabal freeze # writes cabal.project.freeze
# commit it — every machine now resolves the identical plan Et Stack dans tout ça ?
Stack aborde les mêmes objectifs sous un autre angle : au lieu de résoudre les versions par projet, il construit contre des snapshots curés (les resolvers Stackage comme lts-22.x) où tout un ensemble de paquets est connu pour compiler ensemble, et partage les builds globalement par snapshot. Les deux outils sont sains et largement utilisés en 2026 ; la répartition pratique est en gros « je veux la chaîne d’outils standard et un contrôle fin » (Cabal) contre « je veux un ensemble curé et fiable clé en main » (Stack). Ni l’un ni l’autre n’utilise les sandboxes — le concept est pleinement dépassé des deux côtés.
Aide-mémoire de migration
cabal sandbox init → (nothing — just `cabal build`)
cabal sandbox add-source ../lib → packages: . ../lib (in cabal.project)
cabal install --dependencies-only → cabal build --only-dependencies
.cabal-sandbox/ → dist-newstyle/ (local) + ~/.cabal/store (shared)
cabal.sandbox.config → cabal.project (+ cabal.project.freeze) La leçon qu’ont enseignée les sandboxes — ne jamais polluer un état mutable global, isoler par projet — l’a emporté si complètement qu’elle est devenue invisible : c’est simplement la façon dont cabal build se comporte. Si vous lisez ceci parce qu’un vieux lien ou tutoriel vous a pointé vers cabal sandbox init, vous pouvez sans crainte oublier cette commande. Faites simplement cabal build.