Skip to content

Latest commit

 

History

History
723 lines (601 loc) · 26 KB

README.md

File metadata and controls

723 lines (601 loc) · 26 KB

Dependencies

This project now depends on the turtle package in order to illustrate some dependency management basics. The Main.hs executable is a contrived program that uses turtle gratuitously for the echo function:

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Turtle

main :: IO ()
main = echo "Hello, world!"

The release0.nix file is the same as for the previous project except that we now name our package project1 instead of project0, and we've changed the name of the corresponding nix file to project1.nix rather than project0.nix:

let
  pkgs = import <nixpkgs> { };

in
  { project1 = pkgs.haskellPackages.callPackage ./project1.nix { };
  }

... the contents of our project1.nix file have changed as well. This is because our project1.cabal file now has a new turtle dependency:

name: project1
version: 1.0.0
license: BSD3
license-file: LICENSE
cabal-version: >= 1.18
build-type: Simple

executable project1
    build-depends: base < 5, turtle
    main-is: Main.hs
    default-language: Haskell2010

We'll see the corresponding change in the project1.nix generated by cabal2nix:

{ mkDerivation, base, lib, turtle }:
mkDerivation {
  pname = "project1";
  version = "1.0.0";
  src = ./.;
  isLibrary = false;
  isExecutable = true;
  executableHaskellDepends = [ base turtle ];
  license = lib.licenses.bsd3;
}

Notice how neither file specifies what version of turtle to depend on. This is because Nix resembles stack and provides a curated package set of Haskell packages that build together. If you don't specify a version then Nix will pick a version for you.

You can find the latest curated package set here:

... which corresponds roughly to the nixpkgs-unstable release. If you would like to see what package versions Nix selects for a stable release such as nixos-18.09, then change the branch name in the URL from master to release-18.09, like this:

These curated package sets correspond roughly to Stackage resolvers. Stable releases like nixos-18.09 correspond to Stackage LTS resolvers, and the nixpkgs-unstable release corresponds roughly to a Stackage nightly resolver. The main difference is that Nix's package set curation extends beyond Haskell packages: nixpkgs also curates non-Haskell dependencies, too.

We can also see which version our project selects if we build our project using nix-build:

$ nix-build --attr project1 release0.nix
these derivations will be built:
  /nix/store/8g54hjpim7l9s41c9wpcn1h2q8m254m5-project1-1.0.0.drv
building path(s) ‘/nix/store/pi47yvw46xv346brajyrblwqhjmglhaj-project1-1.0.0’
...
Configuring project1-1.0.0...
Dependency base <5: using base-4.9.0.0
Dependency turtle -any: using turtle-1.2.8
...
/nix/store/pi47yvw46xv346brajyrblwqhjmglhaj-project1-1.0.0

The log output from nix-build notes that turtle-1.2.8 was chosen for this build. Your results might vary depending on which version of the nixpkgs channel that you have installed.

Note that nixpkgs only curates the Haskell package set to build against the default version of the GHC compiler. You can display the default compiler version by running the following command:

$ nix-instantiate --eval --expr '(import <nixpkgs> { }).ghc.version'

If you try to change the compiler (as described below) you may need to modify the Haskell package set to get them to build correctly.

Changing versions

Suppose that we want to build against turtle-1.3.0 for whatever reason. This requires a much larger change to our project derivation which we can see in release1.nix:

# Note: This should fail to build
let
  config = {
    packageOverrides = pkgs: rec {
      haskellPackages = pkgs.haskellPackages.override {
        overrides = haskellPackagesNew: haskellPackagesOld: rec {
          project1 =
            haskellPackagesNew.callPackage ./project1.nix { };

          turtle =
            haskellPackagesNew.callPackage ./turtle.nix { };
        };
      };
    };
  };

  pkgs = import <nixpkgs> { inherit config; };

in
  { project1 = pkgs.haskellPackages.project1;
  }

By default, import <nixpkgs> { } will implicitly use an empty or user-defined configuration in ~/.nixpkgs/config.nix or $NIXPKGS_CONFIG. The above configuration overrides that behavior with an explicit config defined within the same file.

This new derivation now references a turtle.nix file generated from cabal2nix by running:

$ cabal2nix cabal://turtle-1.3.2 > turtle.nix

If you try to run that and the command fails with this error message:

cabal2nix: ~/.cabal/packages/hackage.haskell.org/00-index.tar: openBinaryFile: does not exist (No such file or directory)

... then run cabal update and then the error should disappear.

The generated turtle.nix file looks like this:

{ mkDerivation, ansi-wl-pprint, async, base, bytestring, clock
, criterion, directory, doctest, foldl, hostname, lib, managed
, optional-args, optparse-applicative, process, stm, system-fileio
, system-filepath, temporary, text, time, transformers, unix
, unix-compat
}:
mkDerivation {
  pname = "turtle";
  version = "1.3.2";
  sha256 = "f8163bcc08be06883964907391b88c2da0480f4764668629f4ada908319e7b5d";
  libraryHaskellDepends = [
    ansi-wl-pprint async base bytestring clock directory foldl hostname
    managed optional-args optparse-applicative process stm
    system-fileio system-filepath temporary text time transformers unix
    unix-compat
  ];
  testHaskellDepends = [ base doctest ];
  benchmarkHaskellDepends = [ base criterion text ];
  description = "Shell programming, Haskell-style";
  license = lib.licenses.bsd3;
}

nixpkgs uses a callPackage utility function to "tie the knot" when updating dependencies. When we changeturtle this way every package that depends on turtle (including our project1 package) will pick up this new version of turtle.

The nixpkgs manual suggests an alternative approach of specifying package overrides in a shared ~/.nixpkgs/config.nix configuration file. However, I do not recommend this approach: project build instructions should be checked into version control alongside the project so that they stay in sync with the project.

At the time of this writing, if you try to build release1.nix then you will get the following build error:

$ nix-build --attr project1 release1.nix
these derivations will be built:
  /nix/store/r780xwf197a2gxn3008raq5k6xxid8mh-turtle-1.3.0.drv
  /nix/store/y6g5ya8lis6250fcj0mrw1kybjdara9i-project1-1.0.0.drv
building path(s) ‘/nix/store/qmyqayhvy4rxhfkxpdvc1ayc1vyp8nmw-turtle-1.3.0’
...
Configuring turtle-1.3.0...
Setup: Encountered missing dependencies:
optparse-applicative ==0.13.*
builder for ‘/nix/store/r780xwf197a2gxn3008raq5k6xxid8mh-turtle-1.3.0.drv’ failed with exit code 1
cannot build derivation ‘/nix/store/y6g5ya8lis6250fcj0mrw1kybjdara9i-project1-1.0.0.drv’: 1 dependencies couldn't be built
error: build of ‘/nix/store/y6g5ya8lis6250fcj0mrw1kybjdara9i-project1-1.0.0.drv’ failed

This error indicates that we can't upgrade turtle-1.3.0 alone because turtle-1.3.0 depends on optparse-applicative-0.13.* and the default version of optparse-applicative that Nix selects is not in this range. At the time of this writing, Nix picks optparse-applicative-0.12.1.0 as the default version.

We can override the optparse-applicative version using the exact same trick and release2.nix contains this additional override:

# Note: This should also fail to build
let
  config = {
    packageOverrides = pkgs: rec {
      haskellPackages = pkgs.haskellPackages.override {
        overrides = haskellPackagesNew: haskellPackagesOld: rec {
          optparse-applicative =
            haskellPackagesNew.callPackage ./optparse-applicative.nix { };

          project1 =
            haskellPackagesNew.callPackage ./project1.nix { };

          turtle =
            haskellPackagesNew.callPackage ./turtle.nix { };
        };
      };
    };
  };

  pkgs = import <nixpkgs> { inherit config; };

in
  { project1 = pkgs.haskellPackages.project1;
  }

... where ./optparse-applicative.nix is also generated by cabal2nix:

$ cabal2nix cabal://optparse-applicative-0.13.0.0 > optparse-applicative.nix

Now that we've overriden optparse-applicative, we'll run into a different build failure if we are using a sufficiently new revision of nixpkgs:

$ nix-build --attr project1 release2.nix
...
Configuring optparse-applicative-0.13.0.0...
Setup: Encountered missing dependencies:
QuickCheck ==2.8.*
...

Newer versions of nixpkgs select a newer version of QuickCheck than what turtle-1.3.2 requires, so if we want to build against that specific version of turtle then we need to also pin QuickCheck in the same way in release2a.nix:

# Note: This should also fail to build
let
config = {
  packageOverrides = pkgs: rec {
    haskellPackages = pkgs.haskellPackages.override {
      overrides = haskellPackagesNew: haskellPackagesOld: rec {
        optparse-applicative =
          haskellPackagesNew.callPackage ./optparse-applicative.nix { };
        
        QuickCheck =
          haskellPackagesNew.callPackage ./QuickCheck.nix { };
        
        project1 =
          haskellPackagesNew.callPackage ./project1.nix { };
        
        turtle =
          haskellPackagesNew.callPackage ./turtle.nix { };
      };
    };
  };
};

pkgs = import <nixpkgs> { inherit config; };

in
{ project1 = pkgs.haskellPackages.project1;
}

... where QuickCheck.nix is generated by running:

$ cabal2nix cabal://QuickCheck-2.8.2 > QuickCheck.nix

However, that will still fail to build due to a test suite failure in optparse-applicative-0.13.0.0:

$ nix-build --attr project1 release2a.nix
these derivations will be built:
  /nix/store/55b9hxwvknznfdqcksdfp8fqxifgw00p-optparse-applicative-0.13.0.0.drv
  /nix/store/9m816lg47c6wcgmjqpfxsyml4hgc739d-turtle-1.3.0.drv
  /nix/store/las95xi2lzn1lfc75k6acv05yvcw1cc2-project1-1.0.0.drv
building path(s) ‘/nix/store/bgam9vpvqx5j4x8fkasqwws54cqb0pbs-optparse-applicative-0.13.0.0’
...
Running 1 test suites...
Test suite optparse-applicative-tests: RUNNING...
...
=== prop_drops_back_contexts from tests/test.hs:153 ===
*** Failed! Exception: 'tests/dropback.err.txt: openFile: does not exist (No such file or directory)' (after 1 test): 

=== prop_context_carry from tests/test.hs:162 ===
*** Failed! Exception: 'tests/carry.err.txt: openFile: does not exist (No such file or directory)' (after 1 test): 

=== prop_help_on_empty from tests/test.hs:171 ===
*** Failed! Exception: 'tests/helponempty.err.txt: openFile: does not exist (No such file or directory)' (after 1 test): 

=== prop_help_on_empty_sub from tests/test.hs:180 ===
*** Failed! Exception: 'tests/helponemptysub.err.txt: openFile: does not exist (No such file or directory)' (after 1 test): 
...
Test suite optparse-applicative-tests: FAIL
Test suite logged to:
dist/test/optparse-applicative-0.13.0.0-optparse-applicative-tests.log
0 of 1 test suites (0 of 1 test cases) passed.
builder for ‘/nix/store/55b9hxwvknznfdqcksdfp8fqxifgw00p-optparse-applicative-0.13.0.0.drv’ failed with exit code 1
cannot build derivation ‘/nix/store/9m816lg47c6wcgmjqpfxsyml4hgc739d-turtle-1.3.0.drv’: 1 dependencies couldn't be built
cannot build derivation ‘/nix/store/las95xi2lzn1lfc75k6acv05yvcw1cc2-project1-1.0.0.drv’: 1 dependencies couldn't be built
error: build of ‘/nix/store/las95xi2lzn1lfc75k6acv05yvcw1cc2-project1-1.0.0.drv’ failed

However, we can instruct cabal2nix to disable the test suite for our optparse-applicative applicative dependency by running:

$ cabal2nix --no-check cabal://optparse-applicative-0.13.0.0 > optparse-applicative-2.nix

release3.nix uses this test-free optparse-applicative-2.nix file:

let
  config = {
    packageOverrides = pkgs: rec {
      haskellPackages = pkgs.haskellPackages.override {
        overrides = haskellPackagesNew: haskellPackagesOld: rec {
          optparse-applicative =
            haskellPackagesNew.callPackage ./optparse-applicative-2.nix { };

          project1 =
            haskellPackagesNew.callPackage ./project1.nix { };

          turtle =
            haskellPackagesNew.callPackage ./turtle.nix { };
        };
      };
    };
  };

  pkgs = import <nixpkgs> { inherit config; };

in
  { project1 = pkgs.haskellPackages.project1;
  }

... and now the build succeeds:

$ nix-build --attr project1 release3.nix 
these derivations will be built:
  /nix/store/f17zxqqk582my4qfig78yvi6nv0vb588-turtle-1.3.0.tar.gz.drv
  /nix/store/vn2m1agg92fbmwj1h9168jywy5wmarah-turtle-1.3.0.drv
  /nix/store/c3vidydlyaa25kq2zs35kx80vv8sz1mk-project1-1.0.0.drv
these paths will be fetched (1.60 MiB download, 16.92 MiB unpacked):
  /nix/store/9kyi7kr3gzpxns4qalda26ww6jfzbpc7-syb-0.6
  /nix/store/9v640kglbndlrfpr6wpsq626gb2amx40-libssh2-1.7.0-dev
  /nix/store/cm1561r3fs320571n7cicggmjlgy3rdi-unix-compat-0.4.2.0
  /nix/store/hfy7dnf85gp1j8dqlhc2v0fdpsmc02vc-nghttp2-1.10.0
  /nix/store/kmqlvjmkrg66f5pnbx5jknfiyqf09jgx-curl-7.51.0-dev
  /nix/store/l06y84abvix2qmsxs5dbxllfsv9aznfk-hscolour-1.24.1
  /nix/store/pq0dcikqwvxxpiknmwki77nyalba3n4a-doctest-0.11.0
  /nix/store/v0wwvy3ygb52flq49z1yk445w2126rhs-base-compat-0.9.1
  /nix/store/vxqdcfj9kf0k1qvladvxl6wm21np8czh-optparse-applicative-0.13.0.0
  /nix/store/w5v8fjg704a5r38sk5dnf3zz7r8vapac-libev-4.22
  /nix/store/wyvv44zpn9j2fn30m2k2kry2cycqqlqv-ghc-paths-0.1.0.9
  /nix/store/xs8caklddfbmnvkgwcn38m0d7ivxdlq9-mirrors-list
  /nix/store/zdkjkdq4fcc6cwnxddm5mxa64n4pavb8-nghttp2-1.10.0-dev
...
building path(s) ‘/nix/store/frdmdrpr7rgv24i8p5qs5ifvcxz2jm6d-turtle-1.3.0’
...
Configuring turtle-1.3.0...
Dependency ansi-wl-pprint ==0.6.*: using ansi-wl-pprint-0.6.7.3
Dependency async >=2.0.0.0 && <2.2: using async-2.1.0
Dependency base >=4.6 && <5: using base-4.9.0.0
Dependency bytestring >=0.9.1.8 && <0.11: using bytestring-0.10.8.1
Dependency clock >=0.4.1.2 && <0.8: using clock-0.7.2
Dependency directory >=1.0.7 && <1.3: using directory-1.2.6.2
Dependency doctest >=0.7 && <0.12: using doctest-0.11.0
Dependency foldl >=1.1 && <1.3: using foldl-1.2.1
Dependency hostname <1.1: using hostname-1.0
Dependency managed >=1.0.3 && <1.1: using managed-1.0.5
Dependency optional-args >=1.0 && <2.0: using optional-args-1.0.1
Dependency optparse-applicative ==0.13.*: using optparse-applicative-0.13.0.0
Dependency process >=1.0.1.1 && <1.5: using process-1.4.2.0
Dependency stm <2.5: using stm-2.4.4.1
Dependency system-fileio >=0.2.1 && <0.4: using system-fileio-0.3.16.3
Dependency system-filepath >=0.3.1 && <0.5: using system-filepath-0.4.13.4
Dependency temporary <1.3: using temporary-1.2.0.4
Dependency text <1.3: using text-1.2.2.1
Dependency time <1.7: using time-1.6.0.1
Dependency transformers >=0.2.0.0 && <0.6: using transformers-0.5.2.0
Dependency turtle -any: using turtle-1.3.0
Dependency unix >=2.5.1.0 && <2.8: using unix-2.7.2.0
Dependency unix-compat ==0.4.*: using unix-compat-0.4.2.0
...
Building turtle-1.3.0...
Preprocessing library turtle-1.3.0...
[ 1 of 10] Compiling Turtle.Internal  ( src/Turtle/Internal.hs, dist/build/Turtle/Internal.o )
[ 2 of 10] Compiling Turtle.Line      ( src/Turtle/Line.hs, dist/build/Turtle/Line.o )
[ 3 of 10] Compiling Turtle.Shell     ( src/Turtle/Shell.hs, dist/build/Turtle/Shell.o )
[ 4 of 10] Compiling Turtle.Options   ( src/Turtle/Options.hs, dist/build/Turtle/Options.o )
[ 5 of 10] Compiling Turtle.Pattern   ( src/Turtle/Pattern.hs, dist/build/Turtle/Pattern.o )
[ 6 of 10] Compiling Turtle.Format    ( src/Turtle/Format.hs, dist/build/Turtle/Format.o )
[ 7 of 10] Compiling Turtle.Prelude   ( src/Turtle/Prelude.hs, dist/build/Turtle/Prelude.o )
[ 8 of 10] Compiling Turtle.Bytes     ( src/Turtle/Bytes.hs, dist/build/Turtle/Bytes.o )
[ 9 of 10] Compiling Turtle           ( src/Turtle.hs, dist/build/Turtle.o )
[10 of 10] Compiling Turtle.Tutorial  ( src/Turtle/Tutorial.hs, dist/build/Turtle/Tutorial.o )
Preprocessing test suite 'tests' for turtle-1.3.0...
[1 of 1] Compiling Main             ( test/Main.hs, dist/build/tests/tests-tmp/Main.dyn_o )
Linking dist/build/tests/tests ...
Preprocessing test suite 'regression-broken-pipe' for turtle-1.3.0...
[1 of 1] Compiling Main             ( test/RegressionBrokenPipe.hs, dist/build/regression-broken-pipe/regression-broken-pipe-tmp/Main.dyn_o )
Linking dist/build/regression-broken-pipe/regression-broken-pipe ...
running tests
Running 2 test suites...
Test suite tests: RUNNING...
Test suite tests: PASS
Test suite logged to: dist/test/turtle-1.3.0-tests.log
Test suite regression-broken-pipe: RUNNING...
Test suite regression-broken-pipe: PASS
Test suite logged to: dist/test/turtle-1.3.0-regression-broken-pipe.log
2 of 2 test suites (2 of 2 test cases) passed.
...
Configuring project1-1.0.0...
Dependency base <5: using base-4.9.0.0
Dependency turtle -any: using turtle-1.3.0
...
/nix/store/dv0vxc8pwrl8sdrfhy4y2ajnb1nh6qqy-project1-1.0.0

We can look at the difference between optparse-applicative.nix and optparse-applicative-2.nix to see what changed:

$ diff optparse-applicative.nix optparse-applicative-2.nix 
11a12
>   doCheck = false;

The latter file contains a doCheck = false; directive which instructs Nix to not build and run the test suite.

Github dependencies

Suppose that we wish to retrieve our turtle dependency from Github instead of from Hackage. All we have to do is run:

$ cabal2nix https://github.com/Gabriel439/Haskell-Turtle-Library.git --revision ba9c992933ae625cef40a88ea16ee857d1b93e13 > turtle-2.nix

... replacing ba9c992933ae625cef40a88ea16ee857d1b93e13 with the revision we wish to use. You can omit the revision if you want cabal2nix to select the revision of the current master branch.

Result looks like this turtle-2.nix:

{ mkDerivation, ansi-wl-pprint, async, base, bytestring, clock
, criterion, directory, doctest, foldl, hostname, lib, managed
, optional-args, optparse-applicative, process, stm, system-fileio
, system-filepath, temporary, text, time, transformers, unix
, unix-compat
}:
mkDerivation {
  pname = "turtle";
  version = "1.3.2";
  sha256 = "f8163bcc08be06883964907391b88c2da0480f4764668629f4ada908319e7b5d";
  libraryHaskellDepends = [
    ansi-wl-pprint async base bytestring clock directory foldl hostname
    managed optional-args optparse-applicative process stm
    system-fileio system-filepath temporary text time transformers unix
    unix-compat
  ];
  testHaskellDepends = [ base doctest ];
  benchmarkHaskellDepends = [ base criterion text ];
  doBenchmark = true;
  description = "Shell programming, Haskell-style";
  license = lib.licenses.bsd3;
}

release4.nix shows an example of depending on turtle from Github. The only difference is that we now depend on the turtle-2.nix file:

diff release3.nix release4.nix
13c13
<             haskellPackagesNew.callPackage ./turtle.nix { };
---
>             haskellPackagesNew.callPackage ./turtle-2.nix { };

... and the difference between turtle.nix and turtle-2.nix is that the dependency list changed and there is a new src field pointing to the Github repository:

2,5c2,5
< , directory, doctest, foldl, hostname, managed, optional-args
< , optparse-applicative, process, stdenv, stm, system-fileio
< , system-filepath, temporary, text, time, transformers, unix
< , unix-compat
---
> , directory, doctest, fetchgit, foldl, hostname, managed
> , optional-args, optparse-applicative, process, stdenv, stm
> , system-fileio, system-filepath, temporary, text, time
> , transformers, unix, unix-compat
10c10,14
<   sha256 = "0pbvkqqhiaddyhlqcrk48w7li81dijw92wwhchwqh1my1363n5pq";
---
>   src = fetchgit {
>     url = "https://github.com/Gabriel439/Haskell-Turtle-Library.git";
>     sha256 = "0cbs3yi4glqhv3419hxihvpsgcj2h2sirbgym5d45hz4d32n9i67";
>     rev = "21b50f09e04b4e149b3c5a5f12405ed608cda2ab";
>   };

Source dependencies

You can also depend on local source checkouts of a given dependency. For example, if you checkout the turtle repository in some other directory then all you have to do is run:

$ cabal2nix /path/to/turtle > turtle.nix

... and then reference ./turtle.nix in your release.nix file. Now your build will automatically pull in any changes you make to your source checkout of turtle.

Changing the compiler

You can also override the GHC version used to compile your project, which release5.nix illustrates:

{ compiler ? "ghc802" }:

let
  config = {
    packageOverrides = pkgs: rec {
      haskell = pkgs.haskell // {
        packages = pkgs.haskell.packages // {
          "${compiler}" = pkgs.haskell.packages."${compiler}".override {
            overrides = haskellPackagesNew: haskellPackagesOld: rec {
              optparse-applicative =
                haskellPackagesNew.callPackage ./optparse-applicative-2.nix { };

              project1 =
                haskellPackagesNew.callPackage ./project1.nix { };

              turtle =
                haskellPackagesNew.callPackage ./turtle-2.nix { };
            };
          };
        };
      };
    };
  };

  pkgs = import <nixpkgs> { inherit config; };

in
  { project1 = pkgs.haskell.packages.${compiler}.project1;
  }

By default, the above project is built using GHC 8.0.2:

$ nix-build --attr project1 release5.nix
...
Using ghc version 8.0.2 found on system at:
/nix/store/7nl6dii88xd761nnz3xyh11qcnrqvqri-ghc-8.0.2/bin/ghc
Using ghc-pkg version 8.0.2 found on system at:
/nix/store/7nl6dii88xd761nnz3xyh11qcnrqvqri-ghc-8.0.2/bin/ghc-pkg
...
/nix/store/0mw2v9h6f3fz1p9bwy48qxsr5637550s-project1-1.0.0

... but you can now override the compiler on the command line like this:

$ nix-build --argstr compiler ghc7103 --attr project1 release5.nix
...
building path(s) ‘/nix/store/2c5w9j0dam8m2pn35jvbq2namf8y723f-optparse-applicative-0.13.0.0’
setupCompilerEnvironmentPhase
Build with /nix/store/ik664w3cxq2jzr5kby0gwmcm0k96xgmg-ghc-7.10.3.
unpacking sources
unpacking source archive /nix/store/b55m0akvijaxps1lzr424m8y4y4q6awv-optparse-applicative-0.13.0.0.tar.gz
source root is optparse-applicative-0.13.0.0
setting SOURCE_DATE_EPOCH to timestamp 1471231137 of file optparse-applicative-0.13.0.0/tests/test.hs
patching sources
compileBuildDriverPhase
setupCompileFlags: -package-db=/private/var/folders/c9/zf_25xbx7bx8yhsxm4q4vw6m0000gn/T/nix-build-optparse-applicative-0.13.0.0.drv-0/package.conf.d -j8 -threaded
[1 of 1] Compiling Main             ( Setup.hs, /private/var/folders/c9/zf_25xbx7bx8yhsxm4q4vw6m0000gn/T/nix-build-optparse-applicative-0.13.0.0.drv-0/Main.o )
Linking Setup ...
configuring
configureFlags: --verbose --prefix=/nix/store/2c5w9j0dam8m2pn35jvbq2namf8y723f-optparse-applicative-0.13.0.0 --libdir=$prefix/lib/$compiler --libsubdir=$pkgid --with-gcc=clang --package-db=/private/var/folders/c9/zf_25xbx7bx8yhsxm4q4vw6m0000gn/T/nix-build-optparse-applicative-0.13.0.0.drv-0/package.conf.d --ghc-option=-optl=-Wl,-headerpad_max_install_names --disable-split-objs --disable-library-profiling --disable-executable-profiling --enable-shared --disable-coverage --enable-library-vanilla --enable-executable-dynamic --disable-tests
Configuring optparse-applicative-0.13.0.0...
Setup: At least the following dependencies are missing:
semigroups >=0.10 && <0.19
builder for ‘/nix/store/kz5ngjwspkky7677vfcjfkliglsxw8nq-optparse-applicative-0.13.0.0.drv’ failed with exit code 1
cannot build derivation ‘/nix/store/4ll08plvc8wmx31mvvsxs83fg6wp849j-turtle-1.3.2.drv’: 1 dependencies couldn't be built
cannot build derivation ‘/nix/store/q40kf7b4d5xwlrnyrflib3qzdc8vfqly-project1-1.0.0.drv’: 1 dependencies couldn't be built
error: build of ‘/nix/store/q40kf7b4d5xwlrnyrflib3qzdc8vfqly-project1-1.0.0.drv’ failed

Note that the build may fail when you downgrade the compiler. For example, this build fails because of a missing semigroups dependency. This is because of the following clause in the optparse-applicative.cabal file:

  if !impl(ghc >= 8)
    build-depends:     semigroups                      >= 0.10 && < 0.19

... which cabal2nix ignores because it assumes that the current GHC version is GHC 8. However, we can tweak our optparse-applicative dependency to manually add the semigroups dependency in release6.nix:

{ compiler ? "ghc802" }:

let
  config = {
    packageOverrides = pkgs: rec {
      haskell = pkgs.haskell // {
        packages = pkgs.haskell.packages // {
          "${compiler}" = pkgs.haskell.packages."${compiler}".override {
            overrides = haskellPackagesNew: haskellPackagesOld: rec {
              optparse-applicative =
                pkgs.haskell.lib.addBuildDepend
                  (haskellPackagesNew.callPackage ./optparse-applicative-2.nix { })
                  haskellPackagesNew.semigroups;

              project1 =
                haskellPackagesNew.callPackage ./project1.nix { };

              turtle =
                haskellPackagesNew.callPackage ./turtle-2.nix { };
            };
          };
        };
      };
    };
  };

  pkgs = import <nixpkgs> { inherit config; };

in
  { project1 = pkgs.haskell.packages.${compiler}.project1;
  }

... and now the build succeeds:

$ nix-build --argstr compiler ghc7103 --attr project1 release6.nix
...
Using ghc version 7.10.3 found on system at:
/nix/store/ik664w3cxq2jzr5kby0gwmcm0k96xgmg-ghc-7.10.3/bin/ghc
Using ghc-pkg version 7.10.3 found on system at:
/nix/store/ik664w3cxq2jzr5kby0gwmcm0k96xgmg-ghc-7.10.3/bin/ghc-pkg
...
/nix/store/9fmspa6dz93vg84d2c5bl9y1hszxmk7v-project1-1.0.0

The fourth section of this tutorial contains more details on how to tweak Haskell builds.

Conclusion

This concludes basic dependency management in Nix. The next section covers using Nix to manage non-Haskell dependencies.