Page MenuHomeSolus

Haskell stack update
Open, NormalPublic

Description

Haskell stack update

The whole Haskell stack has not been upgraded for almost 4 years now:

PackageCurrently in repoLatest available
ghc8.6.59.6.1
haskell-cabal-install2.4.0.03.10.1.0
haskell-stack2.1.3.12.9.3
pandoc2.53.1.2
...

Problems

There are several factors that make upgrading difficult (which is why it has not been done for so long).

Early on it was decided to provide only dynamically linked binaries for Haskell applications.
This is the way other distros (like Arch) package Haskell apps, so it seemed reasonable at the time.
In theory, it allows the reuse of common library dependencies between applications and results in a smaller footprint of binary artifacts.

However, the reality is that specifically in the Haskell stack there are many more intermediate dependency libraries than actual applications that depend on them.
There are about 300 packages in the stack (reverse dependencies of ghc) and maybe a dozen actual applications.
For example pandoc has almost 100 dependencies by itself.

Moreover, different packages may have conflicting dependencies, requiring either hacking patching these packages, or forcing the upgrade of a lot of dependencies, which might include ghc itself.

This makes upgrading the whole stack and keeping applications up-to-date incredibly difficult and time-consuming.

Solution

Together with the Core Team, we have decided to go away with the dynamic linking approach and rebuild the whole Haskell stack statically.
This means the actual package resolution will be delegated to either cabal or stack freeing us from Haskell dependency hell, which we found ourselves in.
It should greatly reduce the number of maintained packages, eliminate dependency conflicts and enable more frequent application updates.

WIP: the repo will follow the version on Stackage.

However, it will also increase the binary footprint of each application. Although with the number of applications compared to dependencies it is not apparent how cumulative footprint changes if we include all library dependencies.

The only two exceptions to this rule are haskell-cabal-install and xmonad. The former is because Cabal is required to bootstrap the entire stack; the latter is because xmonad changes config by recompiling, so its full dependencies must be available. Consequently, all of the two package dependencies need to be dynamically linked. Fortunately, this list is much smaller, with less than 30 packages needed.

For users who still need to develop Haskell, we will provide ghcup, the official Haskell tool to install GHC, Cabal, Stack, and Haskell Language Server. The ghc, haskell-cabal-install packages in the Solus repo should be used solely for packaging purposes only, not for user use.

Plan

WIP: update the list of packages we need to keep & dynamically link.

  • Deprecate no longer used packages
  • Upgrade ghc from current (9.6.5) to 8.10.7
  • Upgrade ghc from 8.10.7 to 9.2.8
  • Upgrade remaining applications
    • haskell-cabal-install
    • haskell-stack
    • pandoc
    • pandoc-crossref
    • pandoc-citeproc
    • pandoc-include-code
    • shellcheck
    • xmonad
    • xmonad-contrib
    • vgrep
    • bustle
    • cpphs

Event Timeline

As a proof of concept I rebuilt shellcheck with static linking in D14091.

I think it would also make sense to remove haskell- prefix from haskell-cabal-install and haskell-stack after the stack is upgraded.

As well as to add some modern Haskell tooling like ghcup-hs and haskell-language-server.
But this can be done as separate package requests after upgrade.

My personal opinion is that the ghc in our repo is solely for the purpose of packaging. If users/developers want to develop in Haskell, they should install ghcup from our repo and fetch their desired GHC/cabal/stack/hls from ghcup and not from us. Therefore, I don't think there's a need for haskell-language-server. Instead, ghcup should be on a similar important level like ghc and cabal are.

My personal opinion is that the ghc in our repo is solely for the purpose of packaging. If users/developers want to develop in Haskell, they should install ghcup from our repo and fetch their desired GHC/cabal/stack/hls from ghcup and not from us. Therefore, I don't think there's a need for haskell-language-server. Instead, ghcup should be on a similar important level like ghc and cabal are.

Makes sense. For development doing everything via ghcup is indeed way better.
I'll create package request only for ghcup then.

ermo triaged this task as Normal priority.May 4 2023, 4:56 PM
ermo edited projects, added Software, Requires Rebuilds; removed Lacks Project.

Looks like xmonad and xmonad-contrib must provide all their dependencies either way.
xmonad configuration is done by compiling a Haskell script which uses XMonad and other related packages.
And in order to compile it all of the dependencies must be registered in ghc.

So either we need to keep the whole xmonad stack as-is or make it so xmonad and xmonad-contrib package and register all of their dependencies as well.
I cannot figure out how to properly register all dependencies in single package.yml, so that they all end up with proper /usr/lib paths and inside of $installdir (besides copy-pasting installation instructions from several package.yml into one, which doesn't seem like a good solution).

xmonad/xmonad-contrib and its dependencies currently look like this:

tmp.png (539×2 px, 251 KB)