Skip to content

Instantly share code, notes, and snippets.

Last active May 6, 2021
What would you like to do?
Example of overriding a GHC core Haskell package with Nix
# This file is an example of overriding a GHC core Haskell library (like
# bytestring, containers, text, unix, etc) when building a Haskell package.
let default-nixpkgs =
builtins.fetchTarball {
# nixpkgs haskell-updates branch as of 2019/09/15.
url = "";
sha256 = "05d3jxxk5dxzs9b3nan16lhkrjnzf0bjd4xy66az86fsafnrr9rd";
{ nixpkgs ? default-nixpkgs }:
with (import nixpkgs {});
my-haskell-packages = haskell.packages.ghc865.extend (hself: hsuper: rec {
# The bytestring version provided by GHC is This overrides it to use
# bytestring-
# Tests are disabled because they cause circular dependencies.
bytestring = haskell.lib.dontCheck (hself.callHackage "bytestring" "" {});
# We have to make sure that our overriden version of bytestring is used
# instead of the version provided by GHC.
# This is needed because when Nix compiles Haskell packages, it actually passes two
# different GHC package databases to Cabal. The first package database contains
# all the Haskell packages that are distributed with GHC, like bytestring, binary,
# text, etc. The second package database actually contains the Nix-built Haskell
# dependencies, like conduit, lens, etc.
# By default, GHC (Cabal?) picks the highest version of a library it has. So, for instance,
# if we try to pass the bytestring- library in the second package database,
# but bytestring- is already in the first package database, GHC will always
# pick bytestring-, even though we have explicitly overridden the bytestring
# package with in Nix.
# To work around this, we pass a constraint to Cabal that tells it to force
# bytestring- even though there is a later version of bytestring
# available.
# I don't think this would be required if you wanted to go the other way (e.g. use
# bytestring- instead of bytestring-
mkDerivation = drv: (hsuper.mkDerivation drv).override {
configureFlags = [ "--constraint=bytestring==" ];
# The following are all GHC core libraries. We need to build them from
# Hackage so that they have a dependency on our bytestring-
binary = haskell.lib.dontCheck (hself.callHackage "binary" "" {});
directory = hself.callHackage "directory" "" {};
ghc-boot = hself.callHackage "ghc-boot" "8.6.5" {};
ghci = hself.callHackage "ghci" "8.6.5" {};
hpc = hself.callHackage "hpc" "" {};
parsec = hself.callHackage "parsec" "" {};
process = hself.callHackage "process" "" {};
text = hself.callHackage "text" "" {};
unix = hself.callHackage "unix" "" {};
# The Cabal library is a GHC core library, but it is somewhat special because
# it needs to be forced to link to the correct version of bytestring when
# linking the Setup.hs file.
Cabal = haskell.lib.overrideCabal (hself.callHackage "Cabal" "" {}) (oldAttrs: {
preCompileBuildDriver = ''
setupCompileFlags="$setupCompileFlags -package bytestring-"
# doctest needs to be linked to the ghc Haskell package. We are not able
# to override the ghc package with a call to `callHackage` like we do above
# because the `ghc` attribute actually becomes the compiler.
# That is to say, `haskell.packages.ghc865.ghc` is a derivation for the GHC
# compiler, not the ghc Haskell package.
doctest = hsuper.doctest.override {
ghc = hself.ghc_8_6_5;
ghc_8_6_5 = haskell.lib.enableCabalFlag hsuper.ghc_8_6_5 "buildable";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment