It’s generally best to use the default GHC version in nixpkgs, not a version of your choice. This is because the haskell package set is roughly based on Stackage, which requires specific GHC versions. So pkgs.haskellPackages
is generally better than pkgs.haskell.packages.ghcXYZ
unless you know you need the new version and are willing to wade through dependency bounds issues.
That said, many of the issues that crop up when using other GHC versions can be solved by extending the haskell package set and modifying packages or replacing them outright. Here’s how my typical haskell project is set up:
{ pkgs ? import <nixpkgs> {} }:
# packageSourceOverrides is a convenience function
# making it easier to update dependencies to new Hackage versions
# or custom source tree.
(haskellPackages.extend (haskell.lib.packageSourceOverrides {
# Replace the pinned lens version with 4.17 from Hackage.
lens = "4.17";
# Add / replace foo with a git checkout.
# cabal2nix will be called automatically for you
foo = builtins.fetchGit {
url = https://github.com/Foo/foo.git;
rev = "...";
};
# builtins.fetchGit ./. is an easy way to get a clean tree
# from your project. It will even included uncommitted changes,
# but only if they're in tracked files so build dirs like ./dist
# aren't sucked into the nix store unnecessarily.
my-local-pkg = builtins.fetchGit ./.;
})).extend (self: super: {
# We can extend again to add manual overrides
# that can't be done with packageSourceOverrides
# doJailbreak is a very common one. This line replaces bar with
# a modified version that strips the package of its dependency
# bounds, allowing us to use it with newer packages than it
# anticipated.
bar = haskell.lib.doJailbreak super.bar;
})
To build my package, I can do nix-build -A my-local-pkg
, and to enter a nix-shell for incremental building, I can either do nix-shell -A my-local-pkg.env
or add this shell.nix file:
(import ./. {}).my-local-pkg.env
If you’re working on multiple local cabal packages, you can get incrementalism with a cabal.project
file and by replacing env
with shellFor
# cabal.project
packages:
./foo
./bar
# shell.nix
(import ./. {}).shellFor (p: [p.my-local-pkg1 p.my-local-pkg2])
Now nix-shell --run 'cabal new-build all'
can build both packages incrementally.