Skip to content

Instantly share code, notes, and snippets.

@cdepillabout
Last active May 6, 2021
Embed
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 = "https://github.com/NixOS/nixpkgs/archive/a51b3367ab6acc72630da0bad50ce14fa86996d0.tar.gz";
sha256 = "05d3jxxk5dxzs9b3nan16lhkrjnzf0bjd4xy66az86fsafnrr9rd";
};
in
{ nixpkgs ? default-nixpkgs }:
with (import nixpkgs {});
let
my-haskell-packages = haskell.packages.ghc865.extend (hself: hsuper: rec {
# The bytestring version provided by GHC is 0.10.8.2. This overrides it to use
# bytestring-0.10.8.1.
#
# Tests are disabled because they cause circular dependencies.
bytestring = haskell.lib.dontCheck (hself.callHackage "bytestring" "0.10.8.1" {});
# We have to make sure that our overriden 0.10.8.1 version of bytestring is used
# instead of the version 0.10.8.2 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-0.10.8.1 library in the second package database,
# but bytestring-0.10.8.2 is already in the first package database, GHC will always
# pick bytestring-0.10.8.2, even though we have explicitly overridden the bytestring
# package with 0.10.8.1 in Nix.
#
# To work around this, we pass a constraint to Cabal that tells it to force
# bytestring-0.10.8.1 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-0.10.8.3 instead of bytestring-0.10.8.2).
mkDerivation = drv: (hsuper.mkDerivation drv).override {
configureFlags = [ "--constraint=bytestring==0.10.8.1" ];
};
# The following are all GHC core libraries. We need to build them from
# Hackage so that they have a dependency on our bytestring-0.10.8.1.
binary = haskell.lib.dontCheck (hself.callHackage "binary" "0.8.6.0" {});
directory = hself.callHackage "directory" "1.3.3.0" {};
ghc-boot = hself.callHackage "ghc-boot" "8.6.5" {};
ghci = hself.callHackage "ghci" "8.6.5" {};
hpc = hself.callHackage "hpc" "0.6.0.3" {};
parsec = hself.callHackage "parsec" "3.1.13.0" {};
process = hself.callHackage "process" "1.6.5.0" {};
text = hself.callHackage "text" "1.2.3.1" {};
unix = hself.callHackage "unix" "2.7.2.2" {};
# 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" "2.4.0.1" {}) (oldAttrs: {
preCompileBuildDriver = ''
setupCompileFlags="$setupCompileFlags -package bytestring-0.10.8.1"
'';
});
# 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";
});
in
my-haskell-packages.conduit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment