Haskell · Cabal · Build-Werkzeuge
Cabal 2.0: die Version, die Haskell-Builds neu definierte
Cabal 2.0 erschien im September 2017 zusammen mit GHC 8.2, und im Rückblick ist es die Version, die die Ausrichtung des Haskell-Werkzeugbaus für das folgende Jahrzehnt festlegte. Es ist der Moment, in dem drei Dinge auf einen Schlag real wurden: die nix-artigen lokalen Builds, Backpack und ein modernes .cabal-Format mit gesünderer Versionssyntax. Hier, was jedes davon war und wo es heute steht.
1. Nix-artige lokale Builds (new-build)
Die Schlüsselfunktion. Früher isolierten Sandboxes Abhängigkeiten pro Projekt, bauten aber alles von Grund auf neu und waren nicht reproduzierbar. Cabal 2.0 brachte cabal new-build nach vorn: ein inhaltsadressiertes Modell, bei dem jede einzigartige Kombination aus Paket + Version + Optionen + Abhängigkeiten einmal gebaut, unter einem Hash in einem global geteilten Store abgelegt und von jedem Projekt wiederverwendet wird, dessen Build-Plan sie benötigt.
$ cabal new-build # 2017 spelling
$ cabal build # 2026: this IS new-build — it became the default in Cabal 3.0 Stand 2026: Das Präfix new-* ist verschwunden. cabal build, cabal run, cabal repl und cabal test sind alle standardmäßig nix-artig. Die v2--Aliase existieren weiterhin für Skripte; die alten v1--Befehle sind veraltet. Was Cabal 2.0 als Option einführte, ist heute schlicht die Art, wie Cabal funktioniert.
2. Backpack — Mixin-Pakete und Modulsignaturen
Backpack fügte Haskell echte parametrische Modularität hinzu: Eine Bibliothek kann eine Modul-Signatur (eine Schnittstelle) deklarieren und dagegen getypt werden, ohne sich auf eine konkrete Implementierung festzulegen; ein Konsument „mixt“ dann die gewünschte Implementierung ein. Das klassische Beispiel ist eine Bibliothek, die gegen eine abstrakte Str-Signatur geschrieben ist und mit String, striktem Text oder ByteString instanziiert werden kann, ohne Code zu duplizieren.
-- in a .cabal file
library
signatures: Str
exposed-modules: Generic.Algorithm
library impl-text
mixins: indef-lib (Generic.Algorithm as Text.Algorithm)
requires (Str as Data.Text) Stand 2026: Backpack funktioniert und wird weiterhin unterstützt, blieb aber ein Spezialistenwerkzeug statt eines Mainstream-Musters — Typklassen und gewöhnliche Parametrisierung decken die meisten Bedürfnisse ab, und die Werkzeug-/IDE-Unterstützung für Signaturen blieb begrenzt. Greifen Sie darauf zurück, wenn Sie wirklich denselben Code gegen mehrere konkrete Typen kompilieren müssen; sonst begegnet es Ihnen selten.
3. Ein modernes .cabal-Format
Das Setzen von cabal-version: 2.0 schaltete Formatverbesserungen frei, die heute zum Haskell-Alltag gehören:
- Der Caret-Operator
^>=.build-depends: aeson ^>= 2.1bedeutet „>= 2.1 && < 2.2“ — eine kompakte, absichtsklare Art, die obere PVP-Schranke einzuhalten. Man findet ihn überall in modernen Paketen. autogen-modules, damit generierte Module wiePaths_yourpkgkorrekt deklariert und im sdist mitgeliefert werden.- Fremdbibliotheken (die
foreign-library-Stanza), die es erlauben, Haskell-Code als Shared Object zu bauen, um ihn von anderen Sprachen aus zu nutzen. build-dependspro Komponente, damit Bibliothek, Tests und Benchmarks eines Pakets jeweils ihren eigenen präzisen Satz an Abhängigkeiten haben.
Stand 2026: Alles ist Standard. Die heutige Empfehlung lautet, cabal-version: 3.0 oder neuer zu setzen (das impliziert alles, was 2.0 brachte, plus die Common-Stanzas von 2.2, den Platzhalter ** für Datendateien und mehr). Verwenden Sie 2.0 nur, wenn Sie eine sehr alte Toolchain unterstützen müssen.
4. Der Abhängigkeits-Solver wurde besser
Cabal 2.0 lieferte Solver-Verbesserungen, die ihn zugleich schneller machten und eher einen gültigen Installationsplan in einem tiefen Abhängigkeitsgraphen finden ließen, mit klareren Erklärungen, wenn kein Plan existiert. Der Solver hat sich seither weiter verbessert, aber mit 2.0 begann „der Solver funktioniert in der Regel von selbst“ für nicht-triviale Projekte zuzutreffen.
Warum das wichtig war
Vor 2.0 lautete die Geschichte der Haskell-Builds „global installieren und beten“, notdürftig durch Sandboxes geflickt. Nach 2.0 wurde daraus „deklariere, was du willst, erhalte einen reproduzierbaren, geteilten und isolierten Build“ — dasselbe mentale Modell wie bei Nix, Cargo oder modernen Paketmanagern anderswo. Jedes cabal build, das Sie 2026 ausführen, ist der direkte Nachfahre dessen, was 2.0 zum Standardweg machte.
Wenn Sie ein altes Projekt aktualisieren
# Bump the format and modernise bounds:
cabal-version: 3.0 # was 1.x or 2.0
# Replace hand-written ranges with caret bounds where it fits:
build-depends: base ^>= 4.18
, text ^>= 2.0
# Drop any v1-/sandbox era commands from CI; use:
cabal build --enable-tests
cabal test
cabal freeze # commit cabal.project.freeze for reproducibility