Created
April 26, 2015 12:45
-
-
Save bennofs/bd243e58661af62047a5 to your computer and use it in GitHub Desktop.
Overriding with haskell-ng
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{}: # nix-env expects a function | |
let | |
# Get nixpkgs (in configuration.nix, use pkgs for this, but this file is standalone | |
# to test it easier so we have to manually import nixpkgs) | |
pkgs = import <nixpkgs> {}; | |
# First, get the haskell packages from nixpkgs. In configuration.nix, you | |
# can use pkgs.haskellngPackages for this of course. | |
haskellngPackages = pkgs.haskellngPackages; | |
# (this could also be written as inherit (pkgs) haskellngPackages; ) | |
# The ghc-mod expression is defined in nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix as: | |
# "ghc-mod" = callPackage | |
# ({ mkDerivation, async, base, Cabal, ......}: | |
# mkDerivation { | |
# pname = "ghc-mod"; | |
# version = "5.2.1.2"; | |
# sha256 = "11wnrdb6blw169w6kd49ax9h1r9qkka5329lmdhimvki8amv8riv"; | |
# isLibrary = true; | |
# isExecutable = true; | |
# buildDepends = [ async base Cabal ..... ]; | |
# testDepends = [ base Cabal ...... ]; | |
# buildTools = [ emacs makeWrapper ]; | |
# configureFlags = "--datasubdir=ghc-mod-5.2.1.2"; | |
# postInstall = '' | |
# cd $out/share/ghc-mod-5.2.1.2 | |
# make | |
# rm Makefile | |
# cd .. | |
# ensureDir "$out/share/emacs" | |
# mv ghc-mod-5.2.1.2 emacs/site-lisp | |
# ''; | |
# homepage = "http://www.mew.org/~kazu/proj/ghc-mod/"; | |
# description = "Happy Haskell Programming"; | |
# license = stdenv.lib.licenses.bsd3; | |
# }) { inherit (pkgs) emacs; inherit (pkgs) makeWrapper;}; | |
# (..... marks parts that were abbreviated) | |
# | |
# Note that the package is build by a call to the `mkDerivation` function. We would like to pass an additional | |
# argument to mkDerivation such that the expression instead looks like this: | |
# mkDerivation { | |
# pname = "ghc-mod"; | |
# version = "5.2.1.2"; | |
# src = pkgs.fetchgit { | |
# url = https://github.com/kazu-yamamoto/ghc-mod; | |
# rev = "247e4e0e7616fe1fecc68fdcf80d6249ac4cee4f"; | |
# sha256 = "2a23271d0e6907351a246f095040ba18c3ab6bf1cba08a14338d701defa55474"; | |
# # sha256 and rev can be determined using 'nix-prefetch-git https://github.com/kazu-yamamoto/ghc-mod' | |
# }; | |
# .... # rest like above | |
# }) | |
# | |
# This is what the haskell-ng.lib.overrideCabal function allows us to do. | |
# `overrideCabal` expects a function that transforms the old argument set passed | |
# to `mkDerivation` to a new argument set that will be passed to `mkDerivation`. | |
# | |
# So, we can define a new ghc-mod package that overrides the old haskellngPackages.ghc-mod package: | |
ghc-mod-git = pkgs.haskell-ng.lib.overrideCabal haskellngPackages.ghc-mod (oldAttrs: { | |
src = pkgs.fetchgit { | |
url = https://github.com/kazu-yamamoto/ghc-mod; | |
rev = "247e4e0e7616fe1fecc68fdcf80d6249ac4cee4f"; | |
sha256 = "2a23271d0e6907351a246f095040ba18c3ab6bf1cba08a14338d701defa55474"; | |
}; | |
# the new ghc mod also requires some new dependencies. Add them to buildDepends: | |
buildDepends = oldAttrs.buildDepends ++ [ cabal-helper-new haskellngPackages.cereal ]; | |
}); | |
cabal-helper-new = pkgs.haskell-ng.lib.overrideCabal haskellngPackages.cabal-helper (oldAttrs: { | |
version = "0.3.2.0"; | |
sha256 = "06igjmr0n8418wid1pr74cgvlsmwni7ar72g9bddivlbxax1pfli"; | |
}); | |
# The problem with this approach is: all packages that depend on ghc-mod will need to be | |
# changed if they should use the new ghc-mod! | |
# | |
# Also, if haskellngPackages.ghc-mod also depends on cabal-helper, then ghc-mod-git will now | |
# have two versions of cabal-helper in it's build environment! | |
# | |
# If we want reverse dependencies of ghc-mod to see the new ghc-mod too, we need to override | |
# the haskellngPackage set. | |
# To do this, we need an override function. This function takes two arguments: | |
# self: this is the final package set, after all customizations have been applied | |
# (note that this is recursive: it is like 'fix $ \self -> ...' in Haskell) | |
# super: this is the "previous" package set, where previous means before our | |
# customizations have been applied. | |
overrideFunction = self: super: { | |
# Here we just override ghc-mod like above, with one small difference: the package we override is | |
# `super.ghc-mod`, not `haskellngPackages.ghc-mod`. | |
ghc-mod = pkgs.haskell-ng.lib.overrideCabal super.ghc-mod (oldAttrs: { | |
src = pkgs.fetchgit { | |
url = https://github.com/kazu-yamamoto/ghc-mod; | |
rev = "247e4e0e7616fe1fecc68fdcf80d6249ac4cee4f"; | |
sha256 = "2a23271d0e6907351a246f095040ba18c3ab6bf1cba08a14338d701defa55474"; | |
}; | |
# the new ghc mod also requires cereal and cabal-helper now. Add it to buildDepends: | |
# note: we use self.cereal and self.cabal-helper here, so if the package set if | |
# overriden *again* in the future, this package will use the overriden cereal and cabal-helper. | |
buildDepends = oldAttrs.buildDepends ++ [ self.cabal-helper self.cereal ]; | |
}); | |
# ghc-mod from git also requires a newer version of cabal-helper than nixos-unstable contains. | |
cabal-helper = pkgs.haskell-ng.lib.overrideCabal super.cabal-helper (oldAttrs: { | |
version = "0.3.2.0"; | |
sha256 = "06igjmr0n8418wid1pr74cgvlsmwni7ar72g9bddivlbxax1pfli"; | |
}); | |
}; | |
# Now we only need to apply our override function to the haskell package set. | |
# | |
# | |
# We can do this using `.override`. | |
# `.override` allows to change the arguments given to callPackage, and the | |
# haskellngPackage set is just defined as: | |
# haskellngPackages = callPackage ../development/haskell-modules { | |
# ghc = compiler.ghc784; | |
# packageSetConfig = callPackage ../development/haskell-modules/configuration-ghc-7.8.x.nix { }; | |
# } | |
# (it's an alias for packages.ghc784 defined in nixpkgs/pkgs/top-level/haskell-ng.nix) | |
# | |
# With .override, we pass an additional argument when calling ../development/haskell-modules | |
# (which is just nixpkgs/pkgs/development/haskell-modules/default.nix, the file that hooks everything together) called | |
# overrides. This means that customizedPackages is essentially: | |
# haskellngPackages = callPackage ../development/haskell-modules { | |
# ghc = compiler.ghc784; | |
# packageSetConfig = callPackage ../development/haskell-modules/configuration-ghc-7.8.x.nix { }; | |
# overrides = overrideFunction | |
# `haskell-modules/default.nix` will then apply our custom overrides when building the package set. | |
customizedPackages = haskellngPackages.override { | |
overrides = overrideFunction; | |
}; | |
# Now we just take ghc-mod from the customized package set: | |
# By applying the overrides to all of haskellngPackages, all packages that | |
# depend on ghc-mod will also see the new ghc-mod. | |
in customizedPackages.ghc-mod | |
#in ghc-mod-git # ghc-mod-git also works, as explained above. | |
# As said above, | |
# You can test this using: | |
# | |
# nix-build /path/to/this/file.nix | |
# | |
# Or install it to your user environment with: | |
# | |
# nix-env -i -f /path/to/this/file.nix | |
# | |
# You can even see that ghc-mod-git and customizedPackages.ghc-mod are exactly identical: | |
# just change customizedPackages.ghc-mod to ghc-mod-git above, and rebuild. Nix will not | |
# rebuild ghc-mod, but instead just use the already build ghc-mod, since the packages are identical. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This was an extremely helpful and thorough explanation. The past three hours of trying to figure this out have finally come to a close. Thank you!