Skip to content

Latest commit

 

History

History

system-deps

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

System Deps

Sometimes a haskell package will depend on a native library. In Nix this dependency has to be explicitly tracked. In the simple case you would simply create a Nix expression for the haskell library and add the native library to the librarySystemDepends attribute list (example) and add it as an input argument to your expression. The haskellPackages.callPackage function would then take care of finding the appropriate package and supplying it. As the following case-study shows it's sometimes easier said than done.

Real-world scenario - ODBC

The haskell package odbc is marked as broken. But let's try to build it anyway to see where the failure lies:

$ nix-shell -p '(import (import ./pinned-nixpkgs.nix) { config = { allowBroken = true; }; }).haskell.packages.ghc844.ghcWithPackages (pkgs: [ pkgs.odbc ])'
these derivations will be built:
  /nix/store/g2nx6c6y8vbwbkz0vn30wh605gzfbm2r-odbc-0.2.2.drv
  /nix/store/bc5vl2axi5qrdz2jrsx1zb319zamh9ra-ghc-8.4.4-with-packages.drv
building '/nix/store/g2nx6c6y8vbwbkz0vn30wh605gzfbm2r-odbc-0.2.2.drv'...

...

cbits/odbc.c:7:10: error:  fatal error: 'odbcss.h' file not found
  |
7 | #include <odbcss.h>
  |          ^
#include <odbcss.h>
         ^~~~~~~~~~
1 error generated.
`cc' failed in phase `C Compiler'. (Exit code: 1)
builder for '/nix/store/g2nx6c6y8vbwbkz0vn30wh605gzfbm2r-odbc-0.2.2.drv' failed with exit code 1
cannot build derivation '/nix/store/bc5vl2axi5qrdz2jrsx1zb319zamh9ra-ghc-8.4.4-with-packages.drv': 1 dependencies couldn't be built
error: build of '/nix/store/bc5vl2axi5qrdz2jrsx1zb319zamh9ra-ghc-8.4.4-with-packages.drv' failed

As we can see the issue is not in some unmet haskell dependency, but the C compiler is failing to find a header file that is expected from a system library. On non-Nix systems we would simply instruct the user to have the required library installed using the system's package manager, but with nix we have to feed the library to the package that needs it.

We first need the derivations for the system dependencies - we will create a special file system-deps.nix for it. The file will export the 2 libraries that we need. As of right now, setting up unixODBC on non-NixOS systems is quite challenging and so the system-deps.nix is only for the strong soul. This will hopefully improved in the future.

# system-deps.nix
...
in rec {
  freetds = pkgs.freetds.override ...;
  ...
  unixODBC = pkgs.callPackage unixODBCDef ...;
}

Just like in extra-deps we generate a nix expression for odbc and manually add freetds and unixODBC as dependenices in extra-deps.nix:

let

    odbc = { mkDerivation, async, base, bytestring, containers, deepseq
        , fetchgit, formatting, hspec, optparse-applicative, parsec
        , QuickCheck, semigroups, stdenv, template-haskell, text, time
        , transformers, unliftio-core, weigh,
	, unixODBC, freetds # <-------- CHANGE 1 - add native libs as inputs
        }:
        mkDerivation {
          pname = "odbc";
          version = "0.2.3";
          src = fetchgit {
            url = "https://github.com/fpco/odbc";
            sha256 = "0zg1sd160h6hz89w9ln4zjsn6f25nwm6jsj2w8byb638bivvhdvh";
            rev = "a2a3f57edfce2e3e3e25945f8564e6884b4faf38";
            fetchSubmodules = true;
          };
          isLibrary = true;
          isExecutable = true;
          libraryHaskellDepends = [
            async base bytestring containers deepseq formatting parsec
            semigroups template-haskell text time transformers unliftio-core
          ];
          librarySystemDepends = [ unixODBC freetds ]; # <-------- CHANGE 2 - specify the 2 libs as system dependencies
          executableHaskellDepends = [
            base bytestring optparse-applicative text
          ];
          testHaskellDepends = [
            base bytestring hspec parsec QuickCheck text time
          ];
          benchmarkHaskellDepends = [ async base text weigh ];
          homepage = "https://github.com/fpco/odbc";
          description = "Haskell binding to the ODBC API, aimed at SQL Server driver";
          license = stdenv.lib.licenses.bsd3;
        };

    ...

in {
    ...
    odbc = dontCheck (super.callPackage odbc {}); # we also have to disable the tests # <----------- CHANGE 3 - override the package and disable its tests
}

We then need to modify the release.nix file to fix the native libs:

...
  system-deps = import ./system-deps.nix;
  extra-deps = import ./extra-deps.nix;

  config = {
    allowUnfree = true;
    packageOverrides = pkgs: rec {
      inherit (system-deps { inherit pkgs; }) freetds unixODBC; # OVERRIDEN HERE
      haskellPackages = pkgs.haskell.packages.ghc864.override {
        overrides = self: super: ((extra-deps super) // builtins.mapAttrs (name: path: super.callCabal2nix name (gitignore path) {}) (import ./packages.nix));
      };
    };
  };
...

Where:

packageOverrides = pkgs: rec {
  inherit (system-deps { inherit pkgs; }) freetds unixODBC;

is the shorthand for:

packageOverrides = pkgs: let sps = system-deps { pkgs = pkgs; }; in rec {
  freetds = sps.freetds;
  unixODBC = sps.unixODBC;

In the next chapter we will see how to create a virtual environment for your devs.