Haskell · Cabal · strumenti di build
Cabal 2.0: la versione che ridefinì le build Haskell
Cabal 2.0 uscì nel settembre 2017 insieme a GHC 8.2 e, col senno di poi, è la versione che definì l'orientamento degli strumenti Haskell per il decennio successivo. È il momento in cui tre cose divennero reali tutte insieme: le build locali in stile nix, Backpack e un formato .cabal moderno con una sintassi di versione più sana. Ecco cos'era ciascuna e a che punto è oggi.
1. Build locali in stile nix (new-build)
La funzionalità di punta. In precedenza, le sandbox isolavano le dipendenze per progetto ma ricostruivano tutto da zero e non erano riproducibili. Cabal 2.0 promosse cabal new-build: un modello indirizzato per contenuto in cui ogni combinazione unica di pacchetto + versione + opzioni + dipendenze viene costruita una sola volta, memorizzata sotto un hash in uno store globale condiviso, e riutilizzata da ogni progetto il cui piano di build ne abbia bisogno.
$ cabal new-build # 2017 spelling
$ cabal build # 2026: this IS new-build — it became the default in Cabal 3.0 Stato 2026: il prefisso new-* è scomparso. cabal build, cabal run, cabal repl e cabal test sono tutti in stile nix per impostazione predefinita. Gli alias v2- esistono ancora per gli script; i vecchi comandi v1- sono deprecati. Ciò che Cabal 2.0 introdusse come opzione è oggi semplicemente il modo in cui Cabal funziona.
2. Backpack — pacchetti mixin e firme di modulo
Backpack aggiunse a Haskell una vera modularità parametrica: una libreria può dichiarare una firma di modulo (un'interfaccia) ed essere tipata rispetto a essa senza vincolarsi a un'implementazione concreta; un consumatore poi «mixa» l'implementazione che desidera. L'esempio classico è una libreria scritta rispetto a una firma astratta Str che può essere istanziata con String, Text strict o ByteString senza duplicazione di codice.
-- 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) Stato 2026: Backpack funziona ed è tuttora supportato, ma è rimasto uno strumento da specialisti più che uno schema diffuso — le classi di tipo e la parametrizzazione ordinaria coprono la maggior parte delle esigenze, e il supporto di strumenti/IDE per le firme è rimasto limitato. Ricorrici quando hai davvero bisogno di compilare lo stesso codice rispetto a più tipi concreti; altrimenti lo incontrerai di rado.
3. Un formato .cabal moderno
Impostare cabal-version: 2.0 sbloccò miglioramenti di formato che oggi sono il quotidiano di Haskell:
- L'operatore caret
^>=.build-depends: aeson ^>= 2.1significa «>= 2.1 && < 2.2» — un modo compatto e rivelatore d'intento per rispettare il limite superiore del PVP. Lo si trova ovunque nei pacchetti moderni. autogen-modules, affinché i moduli generati comePaths_yourpkgsiano dichiarati correttamente e inclusi nell'sdist.- Librerie esterne (la stanza
foreign-library), che permettono di costruire codice Haskell come oggetto condiviso per essere consumato da altri linguaggi. build-dependsper componente, affinché la libreria, i test e i benchmark di un pacchetto abbiano ciascuno il proprio preciso insieme di dipendenze.
Stato 2026: tutto è standard. La raccomandazione oggi è impostare cabal-version: 3.0 o più recente (implica tutto ciò che 2.0 portava, più le stanze comuni di 2.2, il jolly ** per i file di dati e altro). Usa 2.0 solo se devi supportare una toolchain molto vecchia.
4. Il solver delle dipendenze è migliorato
Cabal 2.0 portò miglioramenti al solver che lo resero al contempo più veloce e più propenso a trovare un piano di installazione valido in un grafo di dipendenze profondo, con spiegazioni più chiare quando nessun piano esiste. Il solver ha continuato a migliorare da allora, ma è con 2.0 che «il solver di solito funziona da solo» iniziò a essere vero per i progetti non banali.
Perché ha contato
Prima di 2.0, la storia delle build Haskell era «installa globalmente e prega», rattoppata dalle sandbox. Dopo 2.0, divenne «dichiara ciò che vuoi, ottieni una build riproducibile, condivisa e isolata» — lo stesso modello mentale di Nix, Cargo o dei gestori di pacchetti moderni altrove. Ogni cabal build che esegui nel 2026 è il discendente diretto di ciò che 2.0 rese la via predefinita.
Se aggiorni un vecchio progetto
# 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