Is it worth switching from Stack to Cabal?

The stack ls tools command will list the tools (principally versions of GHC) that Stack has installed given specified snapshots (if you are using Stack to manage GHC, rather than GHCup) - see ls command - The Haskell Tool Stack.

If that is more versions of GHC than you want, you can delete unwanted ones (the directory and the *.installed file) from Stack’s programs directory (stack path --programs).

If you do not want Stack to install versions of GHC ‘automatically’, Stack can be be configured with the install-ghc option - see Configuration (project and global) - The Haskell Tool Stack.

3 Likes

I recently started using Oleg’s cabal-store-gc (https://github.com/phadej/cabal-extras/tree/master/cabal-store-gc) which helps a lot for this use case. It garbage collects the Cabal store, by default treating executables as GC roots, and you can tell it about projects whose (most recently configured) build configurations will also be GC roots. It would be nice to have a more automatic way for it to keep track of project GC roots rather than needing to remember to run it (once) for each project, but it’s much better than rm -rf ~/.cabal/store.

7 Likes

FWIW, when I first started testing the waters with Haskell a couple of years back, I started off with Stack (which I found to be kind of confusing at the time), and everything went ok. I’ve come back to Haskell in a more real capacity recently, and decided to just use plain ol cabal. IMO it’s actually been quite easy to work with. I needed to learn a little bit about how cabal files work, but mostly it’s been nice and I feel like its quite simple to use now

5 Likes

Switching is usually a matter of running hpack one last time,

How do you go about adding new modules that hpack would just discover in stack? Do you just manually update the deps in the cabal file?

1 Like

I guess you can still run hpack manualy.

I put a Makefile in my projects and just type make build, etc. Then the make rule calls cabal or stack or cargo or npm or …

That way my muscle memory does the same thing, regardless of build system.

And when I use cabal, I have the rule run hpack before calling cabal.

1 Like

Fwiw, cmake in C++ also encourages if not forces you to list individual file manually… people seem often asking for file glob feature.

Perhaps it’s the reason why some sadistic people like me not super bothered by how cabal works by default :).

I consider this one of the ways cabal is still harder to use.

Attempting to follow my own advice, I looked to see if there was an issue about this. There are a few things bouncing around I was able to find. Most importantly for this whole thread, however, is Feature parity with Stack · Issue #8605 · haskell/cabal · GitHub

4 Likes

Since Cabal (cabal-install) removed sandboxes I switched to Stack and with some global settings it keeps a sanity at Haskell development, especially if you (have to) care about disk space usage.

Sane GHC-devel setup:

  • GHCup for compiler & toolchain installation
  • use that GHCup’s version implicitly with system-ghc global option
  • prevent installation of other GHC versions with install-ghc set to false
  • usually also does help to loose upper bounds for compiler and dependencies checks with allow-newer and compiler-check options
  • use stack-clean-old tool to remove snapshot artifacts to keep global storage really lean
  • optionally set resolver to nightly for global projects if using latest GHC version

If I really need older compiler & libs or limit dependencies versions, I do it explicitly per-project. This procedure makes less headaches then pollution prone cabal-install. Now the experience feels on par even with Rust’s Cargo.

2 Likes

I wouldn’t recommend cabal-store-gc as it falls flat in some cases, which leaves cabal store and packages index in invalid state. Happen to me reproducibly with xmonad and xmonad-contrib installs. Even author himself discourages it from normal use as unreliable.

2 Likes

stack-clean-old does handle Stack’s root, beside others. And seems to be reliable in the long run.

1 Like

Something that I don’t see mentioned but is my #1 reason for switching from Stack to Cabal is that HLS support for executables/test suites is incomparably better in Cabal compared to Stack - https://github.com/haskell/haskell-language-server/issues/366

5 Likes

There’s a better option:

4 Likes

That’s good to know. However I use nix integration so stack is installing ghc through nix anyawy. Is there a way to get ghcup use nix as well ?

Search results for ‘ghcup nix’ - Haskell Community

2 Likes

Both the HLS project and the Stack project are keen that HLS support Stack and that Stack can output the information that HLS needs to support Stack (so that HLS does not depend on ‘hacks’). There is an open issue on Stack’s repository in that regard. From my perspective (Stack’s), what I am missing to help - and need to chase - is a precise specification of the information HLS needs that Stack can provide and in what format. I think HLS needs what is ultimately passed to GHC, but Stack does not know that directly - as Stack builds using Cabal (the library), not directly with GHC.

3 Likes

You can invoke anything from within the stack install hook, including nix. The script has to print the location of the ghc binary to stdout.

1 Like

Updo will give you both Cabal and Stack if using projects (stack.yaml and cabal.project).

2 Likes

Regarding Nix integration, you probably mean this thread

If you, or anybody else, finds a good reason not to deprecate it (it seems almost all Nix+cabal users say it only confuses newcomers and leads them away from good solutions) then please let cabal developers know. I’m not a Nix user, so I can’t tell if it’s “identical” to the Nix+stack integration or not, but any comparison and cross-pollination would be very welcome, too.

1 Like

You may know this, but

  • stack-clean-old is useful for cleaning stack-installed tools and libs
  • ghcup tui is useful for cleaning ghcup-installed tools
  • ncdu is useful for exploring these and other disk hogs in more detail

In the limit, I don’t think there’s any difference in disk usage between stack and cabal - you’ll use disk according to the number of GHC versions you need for the projects you’re currently working on. But I guess stack users will more easily accumulate GHC versions if they’re not being careful.

1 Like