diff --git a/doc/languages-frameworks/haskell.section.md b/doc/languages-frameworks/haskell.section.md index c2838c733c7..67318a5b746 100644 --- a/doc/languages-frameworks/haskell.section.md +++ b/doc/languages-frameworks/haskell.section.md @@ -3,1125 +3,11 @@ title: User's Guide for Haskell in Nixpkgs author: Peter Simons date: 2015-06-01 --- + # Haskell - -## How to install Haskell packages - -Nixpkgs distributes build instructions for all Haskell packages registered on -[Hackage](http://hackage.haskell.org/), but strangely enough normal Nix package -lookups don't seem to discover any of them, except for the default version of ghc, cabal-install, and stack: -``` -$ nix-env -i alex -error: selector ‘alex’ matches no derivations -$ nix-env -qa ghc -ghc-7.10.2 -``` - -The Haskell package set is not registered in the top-level namespace because it -is *huge*. If all Haskell packages were visible to these commands, then -name-based search/install operations would be much slower than they are now. We -avoided that by keeping all Haskell-related packages in a separate attribute -set called `haskellPackages`, which the following command will list: -``` -$ nix-env -f "" -qaP -A haskellPackages -haskellPackages.a50 a50-0.5 -haskellPackages.AAI AAI-0.2.0.1 -haskellPackages.abacate abacate-0.0.0.0 -haskellPackages.abc-puzzle abc-puzzle-0.2.1 -haskellPackages.abcBridge abcBridge-0.15 -haskellPackages.abcnotation abcnotation-1.9.0 -haskellPackages.abeson abeson-0.1.0.1 -[... some 14000 entries omitted ...] -``` - -To install any of those packages into your profile, refer to them by their -attribute path (first column): -```shell -nix-env -f "" -iA haskellPackages.Allure ... -``` - -The attribute path of any Haskell packages corresponds to the name of that -particular package on Hackage: the package `cabal-install` has the attribute -`haskellPackages.cabal-install`, and so on. (Actually, this convention causes -trouble with packages like `3dmodels` and `4Blocks`, because these names are -invalid identifiers in the Nix language. The issue of how to deal with these -rare corner cases is currently unresolved.) - -Haskell packages whose Nix name (second column) begins with a `haskell-` prefix -are packages that provide a library whereas packages without that prefix -provide just executables. Libraries may provide executables too, though: the -package `haskell-pandoc`, for example, installs both a library and an -application. You can install and use Haskell executables just like any other -program in Nixpkgs, but using Haskell libraries for development is a bit -trickier and we'll address that subject in great detail in section [How to -create a development environment](#how-to-create-a-development-environment). - -Attribute paths are deterministic inside of Nixpkgs, but the path necessary to -reach Nixpkgs varies from system to system. We dodged that problem by giving -`nix-env` an explicit `-f ""` parameter, but if you call `nix-env` -without that flag, then chances are the invocation fails: -``` -$ nix-env -iA haskellPackages.cabal-install -error: attribute ‘haskellPackages’ in selection path - ‘haskellPackages.cabal-install’ not found -``` - -On NixOS, for example, Nixpkgs does *not* exist in the top-level namespace by -default. To figure out the proper attribute path, it's easiest to query for the -path of a well-known Nixpkgs package, i.e.: -``` -$ nix-env -qaP coreutils -nixos.coreutils coreutils-8.23 -``` - -If your system responds like that (most NixOS installations will), then the -attribute path to `haskellPackages` is `nixos.haskellPackages`. Thus, if you -want to use `nix-env` without giving an explicit `-f` flag, then that's the way -to do it: -```shell -nix-env -qaP -A nixos.haskellPackages -nix-env -iA nixos.haskellPackages.cabal-install -``` - -Our current default compiler is GHC 8.8.x and the `haskellPackages` set -contains packages built with that particular version. Nixpkgs contains the last -three major releases of GHC and there is a whole family of package sets -available that defines Hackage packages built with each of those compilers, -too: -```shell -nix-env -f "" -qaP -A haskell.packages.ghc865 -nix-env -f "" -qaP -A haskell.packages.ghc8101 -``` - -The name `haskellPackages` is really just a synonym for -`haskell.packages.ghc882`, because we prefer that package set internally and -recommend it to our users as their default choice, but ultimately you are free -to compile your Haskell packages with any GHC version you please. The following -command displays the complete list of available compilers: -``` -$ nix-env -f "" -qaP -A haskell.compiler -haskell.compiler.ghc8101 ghc-8.10.1 -haskell.compiler.integer-simple.ghc8101 ghc-8.10.1 -haskell.compiler.ghcHEAD ghc-8.11.20200505 -haskell.compiler.integer-simple.ghcHEAD ghc-8.11.20200505 -haskell.compiler.ghc822Binary ghc-8.2.2-binary -haskell.compiler.ghc844 ghc-8.4.4 -haskell.compiler.ghc863Binary ghc-8.6.3-binary -haskell.compiler.ghc865 ghc-8.6.5 -haskell.compiler.integer-simple.ghc865 ghc-8.6.5 -haskell.compiler.ghc882 ghc-8.8.2 -haskell.compiler.integer-simple.ghc882 ghc-8.8.2 -haskell.compiler.ghc883 ghc-8.8.3 -haskell.compiler.integer-simple.ghc883 ghc-8.8.3 -haskell.compiler.ghcjs ghcjs-8.6.0.1 -``` - -We have no package sets for `jhc` or `uhc` yet, unfortunately, but for every -version of GHC listed above, there exists a package set based on that compiler. -Also, the attributes `haskell.compiler.ghcXYC` and -`haskell.packages.ghcXYC.ghc` are synonymous for the sake of convenience. - -## How to create a development environment - -### How to install a compiler - -A simple development environment consists of a Haskell compiler and one or both -of the tools `cabal-install` and `stack`. We saw in section -[How to install Haskell packages](#how-to-install-haskell-packages) how you can install those programs into your -user profile: -```shell -nix-env -f "" -iA haskellPackages.ghc haskellPackages.cabal-install -``` - -Instead of the default package set `haskellPackages`, you can also use the more -precise name `haskell.compiler.ghc7102`, which has the advantage that it refers -to the same GHC version regardless of what Nixpkgs considers "default" at any -given time. - -Once you've made those tools available in `$PATH`, it's possible to build -Hackage packages the same way people without access to Nix do it all the time: -```shell -cabal get lens-4.11 && cd lens-4.11 -cabal install -j --dependencies-only -cabal configure -cabal build -``` - -If you enjoy working with Cabal sandboxes, then that's entirely possible too: -just execute the command -```shell -cabal sandbox init -``` -before installing the required dependencies. - -The `nix-shell` utility makes it easy to switch to a different compiler -version; just enter the Nix shell environment with the command -```shell -nix-shell -p haskell.compiler.ghc784 -``` -to bring GHC 7.8.4 into `$PATH`. Alternatively, you can use Stack instead of -`nix-shell` directly to select compiler versions and other build tools -per-project. It uses `nix-shell` under the hood when Nix support is turned on. -See [How to build a Haskell project using Stack](#how-to-build-a-haskell-project-using-stack). - -If you're using `cabal-install`, re-running `cabal configure` inside the spawned -shell switches your build to use that compiler instead. If you're working on -a project that doesn't depend on any additional system libraries outside of GHC, -then it's even sufficient to just run the `cabal configure` command inside of -the shell: -```shell -nix-shell -p haskell.compiler.ghc784 --command "cabal configure" -``` - -Afterwards, all other commands like `cabal build` work just fine in any shell -environment, because the configure phase recorded the absolute paths to all -required tools like GHC in its build configuration inside of the `dist/` -directory. Please note, however, that `nix-collect-garbage` can break such an -environment because the Nix store paths created by `nix-shell` aren't "alive" -anymore once `nix-shell` has terminated. If you find that your Haskell builds -no longer work after garbage collection, then you'll have to re-run `cabal -configure` inside of a new `nix-shell` environment. - -### How to install a compiler with libraries - -GHC expects to find all installed libraries inside of its own `lib` directory. -This approach works fine on traditional Unix systems, but it doesn't work for -Nix, because GHC's store path is immutable once it's built. We cannot install -additional libraries into that location. As a consequence, our copies of GHC -don't know any packages except their own core libraries, like `base`, -`containers`, `Cabal`, etc. - -We can register additional libraries to GHC, however, using a special build -function called `ghcWithPackages`. That function expects one argument: a -function that maps from an attribute set of Haskell packages to a list of -packages, which determines the libraries known to that particular version of -GHC. For example, the Nix expression `ghcWithPackages (pkgs: [pkgs.mtl])` -generates a copy of GHC that has the `mtl` library registered in addition to -its normal core packages: -``` -$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: [pkgs.mtl])" - -[nix-shell:~]$ ghc-pkg list mtl -/nix/store/zy79...-ghc-7.10.2/lib/ghc-7.10.2/package.conf.d: - mtl-2.2.1 -``` - -This function allows users to define their own development environment by means -of an override. After adding the following snippet to `~/.config/nixpkgs/config.nix`, -```nix -{ - packageOverrides = super: let self = super.pkgs; in - { - myHaskellEnv = self.haskell.packages.ghc7102.ghcWithPackages - (haskellPackages: with haskellPackages; [ - # libraries - arrows async cgi criterion - # tools - cabal-install haskintex - ]); - }; -} -``` -it's possible to install that compiler with `nix-env -f "" -iA -myHaskellEnv`. If you'd like to switch that development environment to a -different version of GHC, just replace the `ghc7102` bit in the previous -definition with the appropriate name. Of course, it's also possible to define -any number of these development environments! (You can't install two of them -into the same profile at the same time, though, because that would result in -file conflicts.) - -The generated `ghc` program is a wrapper script that re-directs the real -GHC executable to use a new `lib` directory --- one that we specifically -constructed to contain all those packages the user requested: -``` -$ cat $(type -p ghc) -#! /nix/store/xlxj...-bash-4.3-p33/bin/bash -e -export NIX_GHC=/nix/store/19sm...-ghc-7.10.2/bin/ghc -export NIX_GHCPKG=/nix/store/19sm...-ghc-7.10.2/bin/ghc-pkg -export NIX_GHC_DOCDIR=/nix/store/19sm...-ghc-7.10.2/share/doc/ghc/html -export NIX_GHC_LIBDIR=/nix/store/19sm...-ghc-7.10.2/lib/ghc-7.10.2 -exec /nix/store/j50p...-ghc-7.10.2/bin/ghc "-B$NIX_GHC_LIBDIR" "$@" -``` - -The variables `$NIX_GHC`, `$NIX_GHCPKG`, etc. point to the *new* store path -`ghcWithPackages` constructed specifically for this environment. The last line -of the wrapper script then executes the real `ghc`, but passes the path to the -new `lib` directory using GHC's `-B` flag. - -The purpose of those environment variables is to work around an impurity in the -popular [ghc-paths](http://hackage.haskell.org/package/ghc-paths) library. That -library promises to give its users access to GHC's installation paths. Only, -the library can't possible know that path when it's compiled, because the path -GHC considers its own is determined only much later, when the user configures -it through `ghcWithPackages`. So we [patched -ghc-paths](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/patches/ghc-paths-nix.patch) -to return the paths found in those environment variables at run-time rather -than trying to guess them at compile-time. - -To make sure that mechanism works properly all the time, we recommend that you -set those variables to meaningful values in your shell environment, too, i.e. -by adding the following code to your `~/.bashrc`: -```bash -if type >/dev/null 2>&1 -p ghc; then - eval "$(egrep ^export "$(type -p ghc)")" -fi -``` - -If you are certain that you'll use only one GHC environment which is located in -your user profile, then you can use the following code, too, which has the -advantage that it doesn't contain any paths from the Nix store, i.e. those -settings always remain valid even if a `nix-env -u` operation updates the GHC -environment in your profile: -```bash -if [ -e ~/.nix-profile/bin/ghc ]; then - export NIX_GHC="$HOME/.nix-profile/bin/ghc" - export NIX_GHCPKG="$HOME/.nix-profile/bin/ghc-pkg" - export NIX_GHC_DOCDIR="$HOME/.nix-profile/share/doc/ghc/html" - export NIX_GHC_LIBDIR="$HOME/.nix-profile/lib/ghc-$($NIX_GHC --numeric-version)" -fi -``` - -### How to install a compiler with libraries, hoogle and documentation indexes - -If you plan to use your environment for interactive programming, not just -compiling random Haskell code, you might want to replace `ghcWithPackages` in -all the listings above with `ghcWithHoogle`. - -This environment generator not only produces an environment with GHC and all -the specified libraries, but also generates a `hoogle` and `haddock` indexes -for all the packages, and provides a wrapper script around `hoogle` binary that -uses all those things. A precise name for this thing would be -"`ghcWithPackagesAndHoogleAndDocumentationIndexes`", which is, regrettably, too -long and scary. - -For example, installing the following environment -```nix -{ - packageOverrides = super: let self = super.pkgs; in - { - myHaskellEnv = self.haskellPackages.ghcWithHoogle - (haskellPackages: with haskellPackages; [ - # libraries - arrows async cgi criterion - # tools - cabal-install haskintex - ]); - }; -} -``` -allows one to browse module documentation index [not too dissimilar to -this](https://downloads.haskell.org/~ghc/latest/docs/html/libraries/index.html) -for all the specified packages and their dependencies by directing a browser of -choice to `~/.nix-profile/share/doc/hoogle/index.html` (or -`/run/current-system/sw/share/doc/hoogle/index.html` in case you put it in -`environment.systemPackages` in NixOS). - -After you've marveled enough at that try adding the following to your -`~/.ghc/ghci.conf` -``` -:def hoogle \s -> return $ ":! hoogle search -cl --count=15 \"" ++ s ++ "\"" -:def doc \s -> return $ ":! hoogle search -cl --info \"" ++ s ++ "\"" -``` -and test it by typing into `ghci`: -``` -:hoogle a -> a -:doc a -> a -``` - -Be sure to note the links to `haddock` files in the output. With any modern and -properly configured terminal emulator you can just click those links to -navigate there. - -Finally, you can run -```shell -hoogle server --local -p 8080 -``` -and navigate to http://localhost:8080/ for your own local -[Hoogle](https://www.haskell.org/hoogle/). The `--local` flag makes the hoogle -server serve files from your nix store over http, without the flag it will use -`file://` URIs. Note, however, that Firefox and possibly other browsers -disallow navigation from `http://` to `file://` URIs for security reasons, -which might be quite an inconvenience. Versions before v5 did not have this -flag. See -[this page](http://kb.mozillazine.org/Links_to_local_pages_do_not_work) for -workarounds. - -For NixOS users there's a service which runs this exact command for you. -Specify the `packages` you want documentation for and the `haskellPackages` set -you want them to come from. Add the following to `configuration.nix`. - -```nix -services.hoogle = { - enable = true; - packages = (hpkgs: with hpkgs; [text cryptonite]); - haskellPackages = pkgs.haskellPackages; -}; -``` - -### How to install haskell-language-server - -In short: Install `pkgs.haskell-language-server` and use the -`haskell-language-server-wrapper` command to run it. See the [hls -README](https://github.com/haskell/haskell-language-server) on how to configure -your text editor to use hls and how to test your setup. - -Hls needs to be compiled with the ghc version of the project you use it on. - -`pkgs.haskell-language-server` provides `haskell-language-server-wrapper`, -`haskell-language-server`, `haskell-language-server-x.x` and -`haskell-language-server-x.x.x` binaries, where `x.x.x` is the ghc version for -which it is compiled. By default it includes binaries for all ghc versions -that are provided in the binary caches. You can override that list with e.g. - -```nix -pkgs.haskell-language-server.override { supportedGhcVersions = [ "884" "901" ]; } -``` - -When you run `haskell-language-server-wrapper` it will detect the ghc version -used by the project you are working on (by asking e.g. cabal or stack) and pick -the appropriate above mentioned binary from your path. - -Be careful when installing hls globally and using a pinned nixpkgs for a Haskell -project in a nix-shell. If the nixpkgs versions deviate to much (e.g. use -different `glibc` versions) hls might fail. It is recommended to then install hls -in the nix-shell from the nixpkgs version pinned in there. - -If you know, that you only use one ghc version, e.g. in a project specific -nix-shell You can either use an override as given above or simply install -`pkgs.haskellPackages.haskell-language-server` instead of the top-level -attribute `pkgs.haskell-language-server`. - -### How to build a Haskell project using Stack - -[Stack](http://haskellstack.org) is a popular build tool for Haskell projects. -It has first-class support for Nix. Stack can optionally use Nix to -automatically select the right version of GHC and other build tools to build, -test and execute apps in an existing project downloaded from somewhere on the -Internet. Pass the `--nix` flag to any `stack` command to do so, e.g. -```shell -git clone --recurse-submodules https://github.com/yesodweb/wai.git -cd wai -stack --nix build -``` - -If you want `stack` to use Nix by default, you can add a `nix` section to the -`stack.yaml` file, as explained in the [Stack documentation][stack-nix-doc]. For -example: -```yaml -nix: - enable: true - packages: [pkgconfig zeromq zlib] -``` - -The example configuration snippet above tells Stack to create an ad hoc -environment for `nix-shell` as in the below section, in which the `pkgconfig`, -`zeromq` and `zlib` packages from Nixpkgs are available. All `stack` commands -will implicitly be executed inside this ad hoc environment. - -Some projects have more sophisticated needs. For examples, some ad hoc -environments might need to expose Nixpkgs packages compiled in a certain way, or -with extra environment variables. In these cases, you'll need a `shell` field -instead of `packages`: -```yaml -nix: - enable: true - shell-file: shell.nix -``` - -For more on how to write a `shell.nix` file see the below section. You'll need -to express a derivation. Note that Nixpkgs ships with a convenience wrapper -function around `mkDerivation` called `haskell.lib.buildStackProject` to help you -create this derivation in exactly the way Stack expects. However for this to work -you need to disable the sandbox, which you can do by using `--option sandbox relaxed` -or `--option sandbox false` to the Nix command. All of the same inputs -as `mkDerivation` can be provided. For example, to build a Stack project that -including packages that link against a version of the R library compiled with -special options turned on: -```nix -with (import { }); - -let R = pkgs.R.override { enableStrictBarrier = true; }; -in -haskell.lib.buildStackProject { - name = "HaskellR"; - buildInputs = [ R zeromq zlib ]; -} -``` - -You can select a particular GHC version to compile with by setting the -`ghc` attribute as an argument to `buildStackProject`. Better yet, let -Stack choose what GHC version it wants based on the snapshot specified -in `stack.yaml` (only works with Stack >= 1.1.3): -```nix -{nixpkgs ? import { }, ghc ? nixpkgs.ghc}: - -with nixpkgs; - -let R = pkgs.R.override { enableStrictBarrier = true; }; -in -haskell.lib.buildStackProject { - name = "HaskellR"; - buildInputs = [ R zeromq zlib ]; - inherit ghc; -} -``` - -[stack-nix-doc]: http://docs.haskellstack.org/en/stable/nix_integration.html - -### How to create ad hoc environments for `nix-shell` - -The easiest way to create an ad hoc development environment is to run -`nix-shell` with the appropriate GHC environment given on the command-line: -```shell -nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [mtl pandoc])" -``` - -For more sophisticated use-cases, however, it's more convenient to save the -desired configuration in a file called `shell.nix` that looks like this: -```nix -{ nixpkgs ? import {}, compiler ? "ghc7102" }: -let - inherit (nixpkgs) pkgs; - ghc = pkgs.haskell.packages.${compiler}.ghcWithPackages (ps: with ps; [ - monad-par mtl - ]); -in -pkgs.stdenv.mkDerivation { - name = "my-haskell-env-0"; - buildInputs = [ ghc ]; - shellHook = "eval $(egrep ^export ${ghc}/bin/ghc)"; -} -``` - -Now run `nix-shell` --- or even `nix-shell --pure` --- to enter a shell -environment that has the appropriate compiler in `$PATH`. If you use `--pure`, -then add all other packages that your development environment needs into the -`buildInputs` attribute. If you'd like to switch to a different compiler -version, then pass an appropriate `compiler` argument to the expression, i.e. -`nix-shell --argstr compiler ghc784`. - -If you need such an environment because you'd like to compile a Hackage package -outside of Nix --- i.e. because you're hacking on the latest version from Git ----, then the package set provides suitable nix-shell environments for you -already! Every Haskell package has an `env` attribute that provides a shell -environment suitable for compiling that particular package. If you'd like to -hack the `lens` library, for example, then you just have to check out the -source code and enter the appropriate environment: -``` -$ cabal get lens-4.11 && cd lens-4.11 -Downloading lens-4.11... -Unpacking to lens-4.11/ - -$ nix-shell "" -A haskellPackages.lens.env -[nix-shell:/tmp/lens-4.11]$ -``` - -At point, you can run `cabal configure`, `cabal build`, and all the other -development commands. Note that you need `cabal-install` installed in your -`$PATH` already to use it here --- the `nix-shell` environment does not provide -it. - -## How to create Nix builds for your own private Haskell packages - -If your own Haskell packages have build instructions for Cabal, then you can -convert those automatically into build instructions for Nix using the -`cabal2nix` utility, which you can install into your profile by running -`nix-env -i cabal2nix`. - -### How to build a stand-alone project - -For example, let's assume that you're working on a private project called -`foo`. To generate a Nix build expression for it, change into the project's -top-level directory and run the command: -```shell -cabal2nix . > foo.nix -``` -Then write the following snippet into a file called `default.nix`: -```nix -{ nixpkgs ? import {}, compiler ? "ghc7102" }: -nixpkgs.pkgs.haskell.packages.${compiler}.callPackage ./foo.nix { } -``` - -Finally, store the following code in a file called `shell.nix`: -```nix -{ nixpkgs ? import {}, compiler ? "ghc7102" }: -(import ./default.nix { inherit nixpkgs compiler; }).env -``` - -At this point, you can run `nix-build` to have Nix compile your project and -install it into a Nix store path. The local directory will contain a symlink -called `result` after `nix-build` returns that points into that location. Of -course, passing the flag `--argstr compiler ghc763` allows switching the build -to any version of GHC currently supported. - -Furthermore, you can call `nix-shell` to enter an interactive development -environment in which you can use `cabal configure` and `cabal build` to develop -your code. That environment will automatically contain a proper GHC derivation -with all the required libraries registered as well as all the system-level -libraries your package might need. - -If your package does not depend on any system-level libraries, then it's -sufficient to run -```shell -nix-shell --command "cabal configure" -``` -once to set up your build. `cabal-install` determines the absolute paths to all -resources required for the build and writes them into a config file in the -`dist/` directory. Once that's done, you can run `cabal build` and any other -command for that project even outside of the `nix-shell` environment. This -feature is particularly nice for those of us who like to edit their code with -an IDE, like Emacs' `haskell-mode`, because it's not necessary to start Emacs -inside of nix-shell just to make it find out the necessary settings for -building the project; `cabal-install` has already done that for us. - -If you want to do some quick-and-dirty hacking and don't want to bother setting -up a `default.nix` and `shell.nix` file manually, then you can use the -`--shell` flag offered by `cabal2nix` to have it generate a stand-alone -`nix-shell` environment for you. With that feature, running -```shell -cabal2nix --shell . > shell.nix -nix-shell --command "cabal configure" -``` -is usually enough to set up a build environment for any given Haskell package. -You can even use that generated file to run `nix-build`, too: -```shell -nix-build shell.nix -``` - -### How to build projects that depend on each other - -If you have multiple private Haskell packages that depend on each other, then -you'll have to register those packages in the Nixpkgs set to make them visible -for the dependency resolution performed by `callPackage`. First of all, change -into each of your projects top-level directories and generate a `default.nix` -file with `cabal2nix`: -```shell -cd ~/src/foo && cabal2nix . > default.nix -cd ~/src/bar && cabal2nix . > default.nix -``` -Then edit your `~/.config/nixpkgs/config.nix` file to register those builds in the -default Haskell package set: -```nix -{ - packageOverrides = super: let self = super.pkgs; in - { - haskellPackages = super.haskellPackages.override { - overrides = self: super: { - foo = self.callPackage ../src/foo {}; - bar = self.callPackage ../src/bar {}; - }; - }; - }; -} -``` -Once that's accomplished, `nix-env -f "" -qA haskellPackages` will -show your packages like any other package from Hackage, and you can build them -```shell -nix-build "" -A haskellPackages.foo -``` -or enter an interactive shell environment suitable for building them: -```shell -nix-shell "" -A haskellPackages.bar.env -``` - -## Miscellaneous Topics - -### How to build with profiling enabled - -Every Haskell package set takes a function called `overrides` that you can use -to manipulate the package as much as you please. One useful application of this -feature is to replace the default `mkDerivation` function with one that enables -library profiling for all packages. To accomplish that add the following -snippet to your `~/.config/nixpkgs/config.nix` file: -```nix -{ - packageOverrides = super: let self = super.pkgs; in - { - profiledHaskellPackages = self.haskellPackages.override { - overrides = self: super: { - mkDerivation = args: super.mkDerivation (args // { - enableLibraryProfiling = true; - }); - }; - }; - }; -} -``` -Then, replace instances of `haskellPackages` in the `cabal2nix`-generated -`default.nix` or `shell.nix` files with `profiledHaskellPackages`. - -### How to override package versions in a compiler-specific package set - -Nixpkgs provides the latest version of -[`ghc-events`](http://hackage.haskell.org/package/ghc-events), which is 0.4.4.0 -at the time of this writing. This is fine for users of GHC 7.10.x, but GHC -7.8.4 cannot compile that binary. Now, one way to solve that problem is to -register an older version of `ghc-events` in the 7.8.x-specific package set. -The first step is to generate Nix build instructions with `cabal2nix`: -```shell -cabal2nix cabal://ghc-events-0.4.3.0 > ~/.nixpkgs/ghc-events-0.4.3.0.nix -``` -Then add the override in `~/.config/nixpkgs/config.nix`: -```nix -{ - packageOverrides = super: let self = super.pkgs; in - { - haskell = super.haskell // { - packages = super.haskell.packages // { - ghc784 = super.haskell.packages.ghc784.override { - overrides = self: super: { - ghc-events = self.callPackage ./ghc-events-0.4.3.0.nix {}; - }; - }; - }; - }; - }; -} -``` - -This code is a little crazy, no doubt, but it's necessary because the intuitive -version -```nix -{ # ... - - haskell.packages.ghc784 = super.haskell.packages.ghc784.override { - overrides = self: super: { - ghc-events = self.callPackage ./ghc-events-0.4.3.0.nix {}; - }; - }; -} -``` -doesn't do what we want it to: that code replaces the `haskell` package set in -Nixpkgs with one that contains only one entry,`packages`, which contains only -one entry `ghc784`. This override loses the `haskell.compiler` set, and it -loses the `haskell.packages.ghcXYZ` sets for all compilers but GHC 7.8.4. To -avoid that problem, we have to perform the convoluted little dance from above, -iterating over each step in hierarchy. - -Once it's accomplished, however, we can install a variant of `ghc-events` -that's compiled with GHC 7.8.4: -```shell -nix-env -f "" -iA haskell.packages.ghc784.ghc-events -``` -Unfortunately, it turns out that this build fails again while executing the -test suite! Apparently, the release archive on Hackage is missing some data -files that the test suite requires, so we cannot run it. We accomplish that by -re-generating the Nix expression with the `--no-check` flag: -```shell -cabal2nix --no-check cabal://ghc-events-0.4.3.0 > ~/.nixpkgs/ghc-events-0.4.3.0.nix -``` -Now the builds succeeds. - -Of course, in the concrete example of `ghc-events` this whole exercise is not -an ideal solution, because `ghc-events` can analyze the output emitted by any -version of GHC later than 6.12 regardless of the compiler version that was used -to build the `ghc-events` executable, so strictly speaking there's no reason to -prefer one built with GHC 7.8.x in the first place. However, for users who -cannot use GHC 7.10.x at all for some reason, the approach of downgrading to an -older version might be useful. - -### How to override packages in all compiler-specific package sets - -In the previous section we learned how to override a package in a single -compiler-specific package set. You may have some overrides defined that you want -to use across multiple package sets. To accomplish this you could use the -technique that we learned in the previous section by repeating the overrides for -all the compiler-specific package sets. For example: - -```nix -{ - packageOverrides = super: let self = super.pkgs; in - { - haskell = super.haskell // { - packages = super.haskell.packages // { - ghc784 = super.haskell.packages.ghc784.override { - overrides = self: super: { - my-package = ...; - my-other-package = ...; - }; - }; - ghc822 = super.haskell.packages.ghc784.override { - overrides = self: super: { - my-package = ...; - my-other-package = ...; - }; - }; - ... - }; - }; - }; -} -``` - -However there's a more convenient way to override all compiler-specific package -sets at once: - -```nix -{ - packageOverrides = super: let self = super.pkgs; in - { - haskell = super.haskell // { - packageOverrides = self: super: { - my-package = ...; - my-other-package = ...; - }; - }; - }; -} -``` - -### How to specify source overrides for your Haskell package - -When starting a Haskell project you can use `developPackage` -to define a derivation for your package at the `root` path -as well as source override versions for Hackage packages, like so: - -```nix -# default.nix -{ compilerVersion ? "ghc842" }: -let - # pinning nixpkgs using new Nix 2.0 builtin `fetchGit` - pkgs = import (fetchGit (import ./version.nix)) { }; - compiler = pkgs.haskell.packages."${compilerVersion}"; - pkg = compiler.developPackage { - root = ./.; - source-overrides = { - # Let's say the GHC 8.4.2 haskellPackages uses 1.6.0.0 and your test suite is incompatible with >= 1.6.0.0 - HUnit = "1.5.0.0"; - }; - }; -in pkg -``` - -This could be used in place of a simplified `stack.yaml` defining a Nix -derivation for your Haskell package. - -As you can see this allows you to specify only the source version found on -Hackage and nixpkgs will take care of the rest. - -You can also specify `buildInputs` for your Haskell derivation for packages -that directly depend on external libraries like so: - -```nix -# default.nix -{ compilerVersion ? "ghc842" }: -let - # pinning nixpkgs using new Nix 2.0 builtin `fetchGit` - pkgs = import (fetchGit (import ./version.nix)) { }; - compiler = pkgs.haskell.packages."${compilerVersion}"; - pkg = compiler.developPackage { - root = ./.; - source-overrides = { - HUnit = "1.5.0.0"; # Let's say the GHC 8.4.2 haskellPackages uses 1.6.0.0 and your test suite is incompatible with >= 1.6.0.0 - }; - }; - # in case your package source depends on any libraries directly, not just transitively. - buildInputs = [ zlib ]; -in pkg.overrideAttrs(attrs: { - buildInputs = attrs.buildInputs ++ buildInputs; -}) -``` - -Notice that you will need to override (via `overrideAttrs` or similar) the -derivation returned by the `developPackage` Nix lambda as there is no `buildInputs` -named argument you can pass directly into the `developPackage` lambda. - -### How to recover from GHC's infamous non-deterministic library ID bug - -GHC and distributed build farms don't get along well: - - - https://ghc.haskell.org/trac/ghc/ticket/4012 - -When you see an error like this one -``` -package foo-0.7.1.0 is broken due to missing package -text-1.2.0.4-98506efb1b9ada233bb5c2b2db516d91 -``` -then you have to download and re-install `foo` and all its dependents from -scratch: -```shell -nix-store -q --referrers /nix/store/*-haskell-text-1.2.0.4 \ - | xargs -L 1 nix-store --repair-path -``` - -If you're using additional Hydra servers other than `hydra.nixos.org`, then it -might be necessary to purge the local caches that store data from those -machines to disable these binary channels for the duration of the previous -command, i.e. by running: -```shell -rm ~/.cache/nix/binary-cache*.sqlite -``` - -### Builds on Darwin fail with `math.h` not found - -Users of GHC on Darwin have occasionally reported that builds fail, because the -compiler complains about a missing include file: -``` -fatal error: 'math.h' file not found -``` -The issue has been discussed at length in [ticket -6390](https://github.com/NixOS/nixpkgs/issues/6390), and so far no good -solution has been proposed. As a work-around, users who run into this problem -can configure the environment variables -```shell -export NIX_CFLAGS_COMPILE="-idirafter /usr/include" -export NIX_CFLAGS_LINK="-L/usr/lib" -``` -in their `~/.bashrc` file to avoid the compiler error. - -### Builds using Stack complain about missing system libraries - -``` --- While building package zlib-0.5.4.2 using: - runhaskell -package=Cabal-1.22.4.0 -clear-package-db [... lots of flags ...] -Process exited with code: ExitFailure 1 -Logs have been written to: /home/foo/src/stack-ide/.stack-work/logs/zlib-0.5.4.2.log - -Configuring zlib-0.5.4.2... -Setup.hs: Missing dependency on a foreign library: -* Missing (or bad) header file: zlib.h -This problem can usually be solved by installing the system package that -provides this library (you may need the "-dev" version). If the library is -already installed but in a non-standard location then you can use the flags ---extra-include-dirs= and --extra-lib-dirs= to specify where it is. -If the header file does exist, it may contain errors that are caught by the C -compiler at the preprocessing stage. In this case you can re-run configure -with the verbosity flag -v3 to see the error messages. -``` - -When you run the build inside of the nix-shell environment, the system -is configured to find `libz.so` without any special flags -- the compiler -and linker "just know" how to find it. Consequently, Cabal won't record -any search paths for `libz.so` in the package description, which means -that the package works fine inside of nix-shell, but once you leave the -shell the shared object can no longer be found. That issue is by no -means specific to Stack: you'll have that problem with any other -Haskell package that's built inside of nix-shell but run outside of that -environment. - -You can remedy this issue in several ways. The easiest is to add a `nix` section -to the `stack.yaml` like the following: -```yaml -nix: - enable: true - packages: [ zlib ] -``` - -Stack's Nix support knows to add `${zlib.out}/lib` and `${zlib.dev}/include` -as an `--extra-lib-dirs` and `extra-include-dirs`, respectively. -Alternatively, you can achieve the same effect by hand. First of all, run -``` -$ nix-build --no-out-link "" -A zlib -/nix/store/alsvwzkiw4b7ip38l4nlfjijdvg3fvzn-zlib-1.2.8 -``` -to find out the store path of the system's zlib library. Now, you can - - 1. add that path (plus a "/lib" suffix) to your `$LD_LIBRARY_PATH` - environment variable to make sure your system linker finds `libz.so` - automatically. It's no pretty solution, but it will work. - - 2. As a variant of (1), you can also install any number of system - libraries into your user's profile (or some other profile) and point - `$LD_LIBRARY_PATH` to that profile instead, so that you don't have to - list dozens of those store paths all over the place. - - 3. The solution I prefer is to call stack with an appropriate - --extra-lib-dirs flag like so: - ```shell - stack --extra-lib-dirs=/nix/store/alsvwzkiw4b7ip38l4nlfjijdvg3fvzn-zlib-1.2.8/lib build - ``` - -Typically, you'll need `--extra-include-dirs` as well. It's possible -to add those flag to the project's `stack.yaml` or your user's -global `~/.stack/global/stack.yaml` file so that you don't have to -specify them manually every time. But again, you're likely better off -using Stack's Nix support instead. - -The same thing applies to `cabal configure`, of course, if you're -building with `cabal-install` instead of Stack. - -### Creating statically linked binaries - -There are two levels of static linking. The first option is to configure the -build with the Cabal flag `--disable-executable-dynamic`. In Nix expressions, -this can be achieved by setting the attribute: -``` -enableSharedExecutables = false; -``` -That gives you a binary with statically linked Haskell libraries and -dynamically linked system libraries. - -To link both Haskell libraries and system libraries statically, the additional -flags `--ghc-option=-optl=-static --ghc-option=-optl=-pthread` need to be used. -In Nix, this is accomplished with: -``` -configureFlags = [ "--ghc-option=-optl=-static" "--ghc-option=-optl=-pthread" ]; -``` - -It's important to realize, however, that most system libraries in Nix are -built as shared libraries only, i.e. there is just no static library -available that Cabal could link! - -### Building GHC with integer-simple - -By default GHC implements the Integer type using the -[GNU Multiple Precision Arithmetic (GMP) library](https://gmplib.org/). -The implementation can be found in the -[integer-gmp](http://hackage.haskell.org/package/integer-gmp) package. - -A potential problem with this is that GMP is licensed under the -[GNU Lesser General Public License (LGPL)](https://www.gnu.org/copyleft/lesser.html), -a kind of "copyleft" license. According to the terms of the LGPL, paragraph 5, -you may distribute a program that is designed to be compiled and dynamically -linked with the library under the terms of your choice (i.e., commercially) but -if your program incorporates portions of the library, if it is linked -statically, then your program is a "derivative"--a "work based on the -library"--and according to paragraph 2, section c, you "must cause the whole of -the work to be licensed" under the terms of the LGPL (including for free). - -The LGPL licensing for GMP is a problem for the overall licensing of binary -programs compiled with GHC because most distributions (and builds) of GHC use -static libraries. (Dynamic libraries are currently distributed only for macOS.) -The LGPL licensing situation may be worse: even though -[The Glasgow Haskell Compiler License](https://www.haskell.org/ghc/license) -is essentially a "free software" license (BSD3), according to -paragraph 2 of the LGPL, GHC must be distributed under the terms of the LGPL! - -To work around these problems GHC can be build with a slower but LGPL-free -alternative implementation for Integer called -[integer-simple](http://hackage.haskell.org/package/integer-simple). - -To get a GHC compiler build with `integer-simple` instead of `integer-gmp` use -the attribute: `haskell.compiler.integer-simple."${ghcVersion}"`. -For example: -``` -$ nix-build -E '(import {}).haskell.compiler.integer-simple.ghc802' -... -$ result/bin/ghc-pkg list | grep integer - integer-simple-0.1.1.1 -``` -The following command displays the complete list of GHC compilers build with `integer-simple`: -``` -$ nix-env -f "" -qaP -A haskell.compiler.integer-simple -haskell.compiler.integer-simple.ghc7102 ghc-7.10.2 -haskell.compiler.integer-simple.ghc7103 ghc-7.10.3 -haskell.compiler.integer-simple.ghc722 ghc-7.2.2 -haskell.compiler.integer-simple.ghc742 ghc-7.4.2 -haskell.compiler.integer-simple.ghc783 ghc-7.8.3 -haskell.compiler.integer-simple.ghc784 ghc-7.8.4 -haskell.compiler.integer-simple.ghc801 ghc-8.0.1 -haskell.compiler.integer-simple.ghc802 ghc-8.0.2 -haskell.compiler.integer-simple.ghcHEAD ghc-8.1.20170106 -``` - -To get a package set supporting `integer-simple` use the attribute: -`haskell.packages.integer-simple."${ghcVersion}"`. For example -use the following to get the `scientific` package build with `integer-simple`: -```shell -nix-build -A haskell.packages.integer-simple.ghc802.scientific -``` - -### Quality assurance - -The `haskell.lib` library includes a number of functions for checking for -various imperfections in Haskell packages. It's useful to apply these functions -to your own Haskell packages and integrate that in a Continuous Integration -server like [hydra](https://nixos.org/hydra/) to assure your packages maintain a -minimum level of quality. This section discusses some of these functions. - -#### failOnAllWarnings - -Applying `haskell.lib.failOnAllWarnings` to a Haskell package enables the -`-Wall` and `-Werror` GHC options to turn all warnings into build failures. - -#### buildStrictly - -Applying `haskell.lib.buildStrictly` to a Haskell package calls -`failOnAllWarnings` on the given package to turn all warnings into build -failures. Additionally the source of your package is gotten from first invoking -`cabal sdist` to ensure all needed files are listed in the Cabal file. - -#### checkUnusedPackages - -Applying `haskell.lib.checkUnusedPackages` to a Haskell package invokes -the [packunused](http://hackage.haskell.org/package/packunused) tool on the -package. `packunused` complains when it finds packages listed as build-depends -in the Cabal file which are redundant. For example: - -``` -$ nix-build -E 'let pkgs = import {}; in pkgs.haskell.lib.checkUnusedPackages {} pkgs.haskellPackages.scientific' -these derivations will be built: - /nix/store/3lc51cxj2j57y3zfpq5i69qbzjpvyci1-scientific-0.3.5.1.drv -... -detected package components -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - - library - - testsuite(s): test-scientific - - benchmark(s): bench-scientific* - -(component names suffixed with '*' are not configured to be built) - -library -~~~~~~~ - -The following package dependencies seem redundant: - - - ghc-prim-0.5.0.0 - -testsuite(test-scientific) -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -no redundant packages dependencies found - -builder for ‘/nix/store/3lc51cxj2j57y3zfpq5i69qbzjpvyci1-scientific-0.3.5.1.drv’ failed with exit code 1 -error: build of ‘/nix/store/3lc51cxj2j57y3zfpq5i69qbzjpvyci1-scientific-0.3.5.1.drv’ failed -``` - -As you can see, `packunused` finds out that although the testsuite component has -no redundant dependencies the library component of `scientific-0.3.5.1` depends -on `ghc-prim` which is unused in the library. - -### Using hackage2nix with nixpkgs - -Hackage package derivations are found in the -[`hackage-packages.nix`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/hackage-packages.nix) -file within `nixpkgs` and are used as the initial package set for -`haskellPackages`. The `hackage-packages.nix` file is not meant to be edited -by hand, but rather autogenerated by [`hackage2nix`](https://github.com/NixOS/cabal2nix/tree/master/hackage2nix), -which by default uses the [`configuration-hackage2nix.yaml`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/configuration-hackage2nix.yaml) -file to generate all the derivations. - -To modify the contents `configuration-hackage2nix.yaml`, follow the -instructions on [`hackage2nix`](https://github.com/NixOS/cabal2nix/tree/master/hackage2nix). - -## Other resources - - - The Youtube video [Nix Loves Haskell](https://www.youtube.com/watch?v=BsBhi_r-OeE) - provides an introduction into Haskell NG aimed at beginners. The slides are - available at http://cryp.to/nixos-meetup-3-slides.pdf and also -- in a form - ready for cut & paste -- at - https://github.com/NixOS/cabal2nix/blob/master/doc/nixos-meetup-3-slides.md. - - - Another Youtube video is [Escaping Cabal Hell with Nix](https://www.youtube.com/watch?v=mQd3s57n_2Y), - which discusses the subject of Haskell development with Nix but also provides - a basic introduction to Nix as well, i.e. it's suitable for viewers with - almost no prior Nix experience. - - - Oliver Charles wrote a very nice [Tutorial how to develop Haskell packages with Nix](http://wiki.ocharles.org.uk/Nix). - - - The *Journey into the Haskell NG infrastructure* series of postings - describe the new Haskell infrastructure in great detail: - - - [Part 1](https://nixos.org/nix-dev/2015-January/015591.html) - explains the differences between the old and the new code and gives - instructions how to migrate to the new setup. - - - [Part 2](https://nixos.org/nix-dev/2015-January/015608.html) - looks in-depth at how to tweak and configure your setup by means of - overrides. - - - [Part 3](https://nixos.org/nix-dev/2015-April/016912.html) - describes the infrastructure that keeps the Haskell package set in Nixpkgs - up-to-date. +The documentation for the Haskell infrastructure is published at +. The source code for that +site lives in the `doc/` sub-directory of the +[`cabal2nix` Git repository](https://github.com/NixOS/cabal2nix) +and changes can be submitted there.