Currently the haskell.nix overlays replace `haskell` and
`haskellPackages` in the root of pkgs with versions that have just a
fraction of what nixpkgs provides.
Although `haskell-nix.haskellPackages` could be used to provide a much
more complete set there are subtle differences that are likely to cause
issues (and nixpkgs has patches for many haskell packages).
To make it possible for haskell.nix and nixpkgs haskell to coexist,
we need to move the remaining parts of haskell.nix outside of the
`haskell-nix` attribute into `haskell-nix`.
```
ghc -> haskell-nix.ghc
cabal-install -> haskell-nix.cabal-install
haskell.compiler -> haskell-nix.compiler
haskell.packages -> haskell-nix.packages
bootstrap.haskell.compiler -> haskell-nix.bootstrap.compiler
bootstrap.haskell.packages -> haskell-nix.bootstrap.packages
```
The following `haskellPackages` have been removed and instead the
nixpkgs versions will now be in `haskellPackages`. User code should
be updated if the nixpkgs versions are not desired:
```
haskellPackages.hoogle
-> haskell-nix.haskellPackages.hoogle.components.exes.hoogle
haskellPackages.happy
-> haskell-nix.haskellPackages.happy.components.exes.happy
haskellPackages.alex
-> haskell-nix.haskellPackages.alex.components.exes.alex;
```
Guard code has been added to overlays/defaults.nix to prevent us
inadvertently depending on the nixpkgs `haskell` or `haskellPackages`
inside the haskell.nix code base.
10 KiB
User Guide
Haskell.nix can be use for two different use cases:
Use 1 : to build a specific package from hackage or a stackage lts or nightly set.
To build a package, say lens, from a stackage snapshot, say lts-13.28, you could run
nix build '(with import <nixpkgs> (import ./.); haskell-nix.snapshots."lts-13.28").lens.components.library'
which would build the lens library component from the lens package as fixed by the lts-13.28 stackage snapshot.
To build any package from hackage, say lens, in version, say 4.17.1, you could run
nix build '(with import <nixpkgs> (import ./.); (haskell-nix.hackage-package { name = "lens"; version = "4.17.1"; })).components.library'
which would build the lens library component from the lens-4.17.1 package from hackage. The dependencies would be solved against the most recent hackage-index-state that comes via the hackage.nix pin with your haskell.nix checkout. A specific one can be specified as well:
nix build '(with import <nixpkgs> (import ./.); (haskell-nix.hackage-package { name = "lens"; version = "4.17.1"; index-state = "2019-07-14T00:00:00Z"; })).components.library'
which would use the hackage index as of 2019-07-14T00:00:00Z to produce a build plan
for the lens-4.17.1 package.
Use 2 : to build a stack or cabal project.
So you want to use Haskell.nix with your stack or cabal project. The
general approach will be to pick the right tool from nix-tools and
produce a pkgs.nix expression. Getting a copy of the nix-tools
(and potentially the Haskell.nix source), will then equip us to
produce derivations that we can nix build.
Installing nix-tools
To build the latest nix-tools and store the result at ./nt, run:
nix build '(with import <nixpkgs> (import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz)); haskell-nix.nix-tools)' --out-link nt
If you would like to then install nix-tools into your profile, run:
nix-env -i ./nt
Getting the Haskell.nix source (optional)
The Haskell.nix and nix-tools source will be useful if you would
like to contribute improvements, or read the source code to fully
understand something that the documentation doesn't cover.
git clone https://github.com/input-output-hk/nix-tools
git clone https://github.com/input-output-hk/haskell.nix
cd haskell.nix
nix build -f . haskell-nix.nix-tools --out-link nt
Using Haskell.nix with your project
The easiest way to get a hold of Haskell.nix is with
fetchTarball.
import <nixpkgs> (import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz))
Using your cabal.project file
If your project has a cabal.project you can add a default.nix like this:
{ pkgs ? import <nixpkgs> (import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz))
, haskellCompiler ? "ghc865"
}:
pkgs.haskell-nix.cabalProject {
src = pkgs.haskell-nix.haskellLib.cleanGit { src = ./.; };
ghc = pkgs.buildPackages.pkgs.haskell-nix.compiler.${haskellCompiler};
# pkg-def-extras = [
# # Additional packages ontop of all those listed in `cabal.project`
# ];
# modules = [
# # Specific package overrides would go here for example:
# packages.cbors.package.ghcOptions = "-Werror";
# packages.cbors.patches = [ ./one.patch ];
# packages.cbors.flags.optimize-gmp = false;
# # It may be better to set flags in `cabal.project` instead
# # (`plan-to-nix` will include them as defaults).
# ];
}
Note: The cleanGit call will exclude any files not in the index file
in the local .git directory. This is extremely useful as it avoids
unwanted builds (for instance when the contents of dist-newstyle are
modified by cabal). It is important that src is the root directory
of the repo (so cleanGit can find the .git directory). If the project
is not at the root of the repo, then also pass subDir to cleanGit with the
location of the project relative to src as a string. For example:
src = pkgs.haskell-nix.haskellLib.cleanGit
{ src = ./.; subDir = "subdir/another-subdir"; };
You can build a component from your project with nix-build (in this
case the hello executable in a helloworld package):
nix-build -A helloworld.components.exes.hello
For interactive development you can run:
nix-shell -A shellFor
The resulting shell will include all the dependencies of the local packages
listed in your cabal.project file (but it will not build those local
packages).
Inside the shell use cabal new-build and cabal new-repl to work on the
cabal project as you normally would. They will use the packages provided
by nix whenever possible.
It is a good idea to add write-ghc-environment-files: never to your
cabal.project file to prevent unwanted .ghc.environment.* files
(they will prevent subsequent nix-shell invocations from working
properly).
Adding an index-state to your cabal.project can pin the plan used so that
the same packages will be built each time (until you change the index-state
or one of the constraints in your local .cabal files).
Using your stack.yaml file
If your project has a stack.yaml you can add a default.nix like this:
{ pkgs ? import <nixpkgs> (import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz))
}:
pkgs.haskell-nix.stackProject {
src = pkgs.haskell-nix.haskellLib.cleanGit { src = ./.; };
# pkg-def-extras = [
# # Additional packages ontop of all those listed in `stack.yaml`
# ];
# modules = [
# # Specific package overrides would go here for example:
# packages.cbors.package.ghcOptions = "-Werror";
# packages.cbors.patches = [ ./one.patch ];
# packages.cbors.flags.optimize-gmp = false;
# # It may be better to set flags in `stack.yaml` instead
# # (`stack-to-nix` will include them as defaults).
# ];
}
You can build a component from your project with nix-build (in this
case the hello executable in a helloworld package):
nix-build -A helloworld.components.exes.hello
Pinning the Haskell.nix version
For simplicity's sake we will use fetchTarball for the examples in
this documentation. This will always get the latest version, and is
similar to an auto-updating Nix channel.
However, in your own project, you may wish to pin Haskell.nix (as you would pin Nixpkgs). This will make your builds reproducable, more predictable, and faster (because the fixed version is cached).
One way of doing this is to use nix-prefetch-git to get a JSON file
with a revision and SHA-256 hash of Haskell.nix.
$ nix-prefetch-git --quiet https://github.com/input-output-hk/haskell.nix | tee haskell-nix-src.json
{
"url": "https://github.com/input-output-hk/haskell.nix",
"rev": "f1a94a4c82a2ab999a67c3b84269da78d89f0075",
"date": "2019-06-05T01:06:12+00:00",
"sha256": "0ggxsppjlb6q6a83y12cwgrdnqnw1s128rpibgzs5p1966bdfqla",
"fetchSubmodules": false
}
(The tee command is just to show you the result.)
Use the following expression to import that version:
{ nixpkgs ? <nixpkgs> }:
let
spec = builtins.fromJSON (builtins.readFile ./haskell-nix-src.json);
haskell-nix-src = (import nixpkgs {}).fetchgit {
name = "haskell-lib";
inherit (spec) url rev sha256 fetchSubmodules;
};
in
import nixpkgs (import haskell-nix-src)
There are other possible schemes for pinning. See
haskell.nix/lib/fetch-external.nix,
the niv tool, or the Nix Flakes
proposal.
Overriding the Hackage version
Sometimes you might want to use a chosen version of Haskell.nix with a recent update of Hackage or Stackage. This can be done with JSON pins:
nix-prefetch-git https://github.com/input-output-hk/hackage.nix | tee hackage-src.json
nix-prefetch-git https://github.com/input-output-hk/stackage.nix | tee stackage-src.json
The resulting JSON files will correspond to the latest revision of hackage.nix and stackage.nix. See Architecture for more information about how these Git repositories correspond to the actual Hackage and Stackage.
{ pkgs ? import <nixpkgs> (haskellNixArgs // { overlays = haskellNixArgs.overlays ++ [
(self: super: {
haskell-nix = super.haskell-nix // {
hackageSourceJSON = ./hackage-src.json;
stackageSourceJSON = ./stackage-src.json;
};
})]; })
, haskellNixArgs ? import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz)
}:
pkgs
Using nix repl
It's sometimes useful to load Haskell.nix in the REPL to explore attrsets and try examples.
# example.nix
{ nixpkgs ? <nixpkgs> }:
rec {
haskell = import nixpkgs (import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz));
pkgNames = haskell.pkgs.lib.attrNames haskell.haskell-nix.snapshots."lts-13.18";
}
Load the example file:
$ nix repl '<nixpkgs>' example.nix
Welcome to Nix version 2.3pre6631_e58a7144. Type :? for help.
Loading '<nixpkgs>'...
Added 10403 variables.
Loading 'example2.nix'...
Added 2 variables.
nix-repl> lib.take 5 pkgNames
[ "ALUT" "ANum" "Allure" "Boolean" "BoundedChan" ]
nix-repl>
Now that you have nix-tools and are able to import Haskell.nix,
you can continue to the next chapter.