coldwa.st
Alle LeitfädenProgrammierungWebDatenWerkzeugeDatenbankenHaskellKonzepteCabal & BuildsToolchainCompilerPerformanceEditor & HLS

Haskell · Cabal · Build-Werkzeuge

Cabal 2.0: die Version, die Haskell-Builds neu definierte

Von ColdwastAktualisiert am 13. Juni 20267 Min. Lesezeit#haskell#cabal#build
Ein Abhängigkeitsgraph und ein Terminal, das cabal new-build ausführt und die nix-artigen Builds von Cabal 2.0 veranschaulicht
Cabal 2.0 machte die nix-artige projektbezogene Planung zum Fundament der modernen Toolchain.
Aktualisierte, von der Community gepflegte Neufassung — eigenständige Inhalte, weder vom früheren Domain-Inhaber verfasst noch mit ihm verbunden. Wo sich Fakten von 2017 seither geändert haben, wird der Stand von 2026 ausdrücklich gekennzeichnet.

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.1 bedeutet „>= 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 wie Paths_yourpkg korrekt 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-depends pro 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

Quellcode geöffnet in einem Code-Editor
Quellcode geöffnet in einem Code-Editor

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

Lesen Sie auch: Die Cabal-Sandboxes und was sie ersetzt hat · cabal-install parallelisieren · alle Leitfäden