[ANN] Cabal-3.12.0.0 released!

Dear everyone,

the Cabal team is happy to announce the release of Cabal the library version 3.12.0.0 and the companion pre-release of cabal-install (the commandline tool; scroll down for more information).

What is new?

There are a number of new features in this release (Cabal) and pre-release (cabal-install), such as:

  • Add support for asm, cmm, and js sources in executable components.
  • Add --haddock-output-dir flag to cabal haddock.
  • Add --semaphore option to ./Setup build interface.
  • Add --promised-dependency flag to ./Setup configure interface.
  • Add the ability to --ignore specific checks to cabal check.
  • Add support for GHC2024 language edition.
  • Add support for loading multiple components into one repl session (especially important for HLS users).
  • Add cabal path command.
  • Add support for authentication tokens for uploading to Hackage.
  • Allow more flags in the init section of config file.
  • Add --semaphore flag to enable interaction with GHC Job Server protocol.
  • Adds functionality for the --offline flag with the build command.
  • Improve solver rejections in brevity and accuracy.

There is much more: for a detailed list of enhancements, changes, and bugfixes, please check the Cabal-3.12.0.0 changelog (and the cabal-install 3.12.0.0-prerelease changelog).

Authors and contributors

Cabal is a collaborative effort; these people contributed with code to this release:

aleeusgr
Adam Gundry
Andrea Bedini
Andreas Abel
Andreas Klebinger
Arjun Kathuria
Artem Pelenitsyn
BasLaa
Bas Laarakker
Ben Gamari
Bodigrim
Brandon Chinn
Brandon S. Allbery
Bryan Richter
Colton Clemmer
Csaba Hruska
cydparser
Daniel Trstenjak
David Binder
David Christiansen
Edwin Marshall
Elodie Lander
Erik de Castro Lopo
Felix Yan
Fendor
Finley
Francesco Ariis
Francesco Gazzetta
Fraser Tweedale
Gershom Bazerman
Hamish Mackenzie
Hécate Moonlight
Ikko Eltociear Ashimine
Jana Chadt
Javier Sagredo
Jean-Paul Calderone
Jens Petersen
Jessica Hamilton
John Paul Adrian Glaubitz
Josh Meredith
Julia Longtin
Julian Ospald
Kazuki Okamoto
Kleidukos
Kristen Kozak
Krzysztof Gogolewski
liamzee
Liisi Kerik
Lin Runze
malteneuss
Malte Neuss
Marcin Szamotulski
Matthew Pickering
Mel Zuser
Michael Peyton Jones
Mike Pilgrem
Mikolaj Konarski
mixphix
Oleg Grenrus
Ondřej Šebek
Patrick Augusto
Patrick Dougherty
Phil de Joux
Pierre Le Marre
Rebecca Turner
Rodrigo Mesquita
Ryan Scott
Samuel Thibault
Sander
Sebastian Tee
Sergey Vinokurov
Shae Erisson
sheaf
Simon Hengel
Siyuan Chen
Sören Tempel
Suganya Raju
Sylvain Henry
Taylor Fausak
Teo Camarasu
Tom Ellis
Tom Smeding
Torsten Schmits
Tristan Cacqueray
Troels Henriksen
Wismill
Yvan Sraka

The release could not be done without the help of the manual QA team and devops people, we thank them both. Thanks also to the many users who provided bug reports and suggestions for improvements.

A special mention to @Kleidukos, who recently stepped down from Cabal release coordination and left the process in a better, more organised shape than what was before.

How to get the cabal-install pre-release

This release is a Cabal-the-library release, but if you want to test the new features of cabal-install, you can download the pre-release of the commandline tool via GHCup. Use one of the following commands, depending on your OS:

ghcup --no-cache install cabal -u 'https://gitlab.haskell.org/haskell/cabal/-/jobs/1848320/artifacts/raw/out/cabal-install-3.11.0.0-x86_64-linux-alpine3_12.tar.xz' 3.12.0.0-prerelease

ghcup --no-cache install cabal -u 'https://gitlab.haskell.org/haskell/cabal/-/jobs/1848326/artifacts/raw/out/cabal-install-3.11.0.0-aarch64-darwin.tar.xz' 3.12.0.0-prerelease

ghcup --no-cache install cabal -u 'https://gitlab.haskell.org/haskell/cabal/-/jobs/1848327/artifacts/raw/out/cabal-install-3.11.0.0-x86_64-windows.zip' 3.12.0.0-prerelease

or an analogous command for any other of the artifacts produced by the pre-release pipeline.

How to help?

Cabal is a complex piece of software running on many different machine. Two easy ways to help the development team producing quality releases are:

  • Join the manual QA team.
  • Test nightly binary cabal-install snapshots and pre-releases (such as the 3.12.0.0 pre-release mentioned above) and report any problem you find.
42 Likes

A personal thank you to @Mikolaj, who guided me through the release process and to each cabal contributor who helped 3.12, you are a lovely bunch to work with!

8 Likes

It was a pleasure. :slight_smile:

4 Likes

Congratulations to the teams involved!

I am delighted to be able to use this pre-release on my project.

6 Likes

For multiple components, is that within a single package (e.g. lib, exe, tests)? Or can I load across packages if I have a multi-package cabal.project sort of setup?

2 Likes

Is HLS prepared to work with this version of cabal? I really missed this feature. Congrats!

2 Likes

Amazing work!

Unless I’m missing something, it looks like this isn’t listed in the changelog.

1 Like

It’s listed in the other changelog, so you are getting it in the unofficial cabal-install pre-release and in cabal-install 3.12.1.0 once it’s out.

3 Likes

For reference, I did a little measurement, using hyperfine with different versions of GHC, using -j and --semaphore, building the Servant monorepo on a 12-cores machine:

$ hyperfine --prepare "cabal clean" "cabal build --with-compiler ghc-9.6 -O1 -j all" "cabal build --with-compiler ghc-9.8 -O1 -j all" "cabal build --with-compiler ghc-9.8 -O1 --semaphore all"

Benchmark 1: cabal build --with-compiler ghc-9.6 -O1 -j all
  Time (mean ± σ):     84.771 s ±  1.139 s    [User: 597.304 s, System: 92.978 s]
  Range (min … max):   83.351 s … 87.272 s    10 runs
 
Benchmark 2: cabal build --with-compiler ghc-9.8 -O1 -j all
  Time (mean ± σ):     40.627 s ±  0.558 s    [User: 226.383 s, System: 58.612 s]
  Range (min … max):   39.931 s … 41.884 s    10 runs
 
Benchmark 3: cabal build --with-compiler ghc-9.8 -O1 --semaphore all
  Time (mean ± σ):     39.953 s ±  0.195 s    [User: 225.265 s, System: 58.264 s]
  Range (min … max):   39.578 s … 40.235 s    10 runs
 
Summary
  cabal build --with-compiler ghc-9.8 -O1 --semaphore all ran
    1.02 ± 0.01 times faster than cabal build --with-compiler ghc-9.8 -O1 -j all
    2.12 ± 0.03 times faster than cabal build --with-compiler ghc-9.6 -O1 -j all

No extraordinary perf gains on this codebase with --semaphore, but I’m interested in other people’s benchmark results!

4 Likes

To make the prereleases properly accessible to GHCup users, the release team should:

6 Likes

HLS is prepared for cabal’s multi-repl feature. There are some small caveats, though:

  • HLS 2.8.0.0 (not available in ghcup yet, iirc) supports the multi-repl feature but doesn’t use it by default. You have to enable it by explicitly setting the LSP option "sessionLoading": "multiComponent". How you specify this option depends on your LSP client. The respective vscode-haskell release that adds support for this option is yet to happen, as we are bogged down by GitHub CI issues.

  • HLS 2.7.0.0 also supports the mutli-repl feature already, and will use it by default if cabal-install 3.12 is installed on your system and you load more than one component. In other words, you use the experimental multi-repl feature if you load a library and executable into the HLS session and cabal-install 3.12 is on the $PATH.

7 Likes

Congratulations and thank you to everyone involved!

I personally think the multiple home units support will be a big boost for the scalability of Haskell codebases. There are many benefits to splitting projects up into multiple packages, both for the project itself but also for the sake of the ecosystem.

I’ve worked on multiple projects in the past where we wanted to open-source a lot of useful functionality, but we were reluctant to do so because that would’ve required us to extract parts of the mono-package that are actively developed in tandem with downstream modules that depend on the. But without multiple home units support, splitting up packages like that is a recipe for disaster for fast development iterations and IDE support. So, I’m really excited by this development, not only for my own convenience, but also due to how I think it will benefit the ecosystem.

7 Likes

The 3.12.0.0-prerelease cabal binary reports

$ cabal --version
cabal-install version 3.11.0.0
compiled using version 3.12.0.0 of the Cabal library

so that will probably not trigger the multi-repl feature with HLS 2.7.0.0, right? The proper 3.12.1.0 release should, though (and HLS 2.8.0.0 doesn’t care).

Mostly we switched 2.8 to require explicit opt-in as the feature is still new, and might have some issues to shake out. In future we intend to make it the default (when you have tool versions that support it). But please do try it out and give us feedback!

1 Like

I think this should use the multi-repl feature as well, we require the cabal-install version to be >= 3.11, so it will trigger the multi-repl feature with HLS 2.7.0.0

1 Like

You’re absolutely right. Starting with the next one, all pre-releases will be properly moved to downloads.haskell.org and will use the pre-release channel, which is also a nice opportunity for users to discover GHC versions. Thanks for raising this.

But without multiple home units support, splitting up packages like that is a recipe for disaster for fast development iterations and IDE support

I understand the usefulness of multiple home units in the repl, but here I’m using haskell-language-server 2.6.0 on a multi-package project and it seems to work well. Changes in one package are reflected when I go edit another one.

So what will multiple home units add on top of that? What are their advantages for packages with multiple libraries, or projects with multiple packages?

2 Likes

It works fine for small projects. You don’t notice the fact that whenever you change anything in package a all the dependent modules in a need to be recompiled before any module in package b can be reloaded.

Now think about a project with 300 modules all happily living in a single cabal stanza. You’re working on module B and module A in tandem, where module B imports module A. Any time you change anything in A you reload and only module A and then module B get reloaded. Then you split this project into two packages and A ends up in package a with 150 other modules, many of which transitively depend on A (but module B doesn’t depend on them). Now if you change anything in A, you need to wait for all the dependents of A in a to get recompiled before you can reload B.

The situation I describe might sound contrived, but it actually happens a lot with modules like Utils. It also happens a lot when you’re working on the tests in a very large project.

3 Likes

At my job we have 1000s of modules and actually default to having ghci not load any of them - you explicitly :load and it only builds what you need.

Being able to have this workflow across package boundaries will definitely be big for us!

1 Like

Any time you change anything in A you reload and only module A and then module B get reloaded.

Are you referring to reloading in ghci / cabal repl, or to having feedback from HLS after a change? Because, in your example, HLS would eventually recompile the 150 other modules, wouldn’t it?