coldwa.st
Tutte le guideProgrammazioneWebDatiStrumentiDatabaseHaskellConcettiCabal e buildToolchainCompilatorePrestazioniEditor e HLS

Haskell · Cabal · strumenti di build

Cabal 2.0: la versione che ridefinì le build Haskell

Di ColdwastAggiornato il 13 giugno 20267 min di lettura#haskell#cabal#build
Un grafo delle dipendenze e un terminale che esegue cabal new-build, a illustrare le build in stile nix di Cabal 2.0
Cabal 2.0 fece della pianificazione per progetto in stile nix il fondamento della toolchain moderna.
Riscrittura aggiornata, mantenuta dalla community — contenuto originale, non scritto dal precedente proprietario del dominio né affiliato a esso. Laddove fatti del 2017 sono cambiati da allora, lo stato 2026 è segnalato esplicitamente.

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.1 significa «>= 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 come Paths_yourpkg siano 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-depends per 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

Codice sorgente aperto in un editor di codice
Codice sorgente aperto in un editor di codice

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

Leggi anche: Le sandbox Cabal e ciò che le ha sostituite · Parallelizzare cabal-install · tutte le guide