diff options
author | Peter Simons <simons@cryp.to> | 2020-10-22 10:37:11 +0200 |
---|---|---|
committer | Peter Simons <simons@cryp.to> | 2020-10-23 21:00:26 +0200 |
commit | 5fe0939d18d4303440c97afcf24a1c5b44e1c285 (patch) | |
tree | 80e0a39c0a47811308e02348dd167352d91bbdb3 /doc | |
parent | 7f7a12f20ea2a91f07e628ea9d5e97a45ed5e609 (diff) |
The Haskell documentation has moved to <https://haskell4nix.readthedocs.io/>.
That site is generated automatically from the set of text files found at
<https://github.com/NixOS/cabal2nix/tree/master/doc>.
Diffstat (limited to 'doc')
-rw-r--r-- | doc/languages-frameworks/haskell.section.md | 1126 |
1 files changed, 6 insertions, 1120 deletions
diff --git a/doc/languages-frameworks/haskell.section.md b/doc/languages-frameworks/haskell.section.md index c2838c733c72..67318a5b7467 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 "<nixpkgs>" -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 "<nixpkgs>" -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 "<nixpkgs>"` 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 "<nixpkgs>" -qaP -A haskell.packages.ghc865 -nix-env -f "<nixpkgs>" -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 "<nixpkgs>" -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 "<nixpkgs>" -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 "<nixpkgs>" -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 <nixpkgs> { }); - -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 <nixpkgs> { }, 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 <nixpkgs> {}, 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 "<nixpkgs>" -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 <nixpkgs> {}, compiler ? "ghc7102" }: -nixpkgs.pkgs.haskell.packages.${compiler}.callPackage ./foo.nix { } -``` - -Finally, store the following code in a file called `shell.nix`: -```nix -{ nixpkgs ? import <nixpkgs> {}, 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 "<nixpkgs>" -qA haskellPackages` will -show your packages like any other package from Hackage, and you can build them -```shell -nix-build "<nixpkgs>" -A haskellPackages.foo -``` -or enter an interactive shell environment suitable for building them: -```shell -nix-shell "<nixpkgs>" -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 "<nixpkgs>" -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-wor |