Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add package to cabal2nix generated `env`?

I use this default.nix to build my package with nix-build and get the env with nix-shell

{ pkgs ? import <nixpkgs> {} }:
with pkgs;
with haskellPackages;

let
  myPackage = callPackage ./myPackage.nix {};
in
  if lib.inNixShell then myPackage.env else myPackage

myPackage.nix generated using cabal2nix . > myPackage.nix

{ mkDerivation, base, split, stdenv }:
mkDerivation {
  pname = "myPackage";
  version = "0.1.0.0";
  src = ./.;
  isLibrary = false;
  isExecutable = true;
  executableHaskellDepends = [ base split ];
  license = stdenv.lib.licenses.bsd3;
}

This working fine for building but I want to add development helper tools while I working on it. I don't want to edit myPackage.nix. I want to re-run cabal2nix when I edit myPackage.cabal.

I try to use buildInputs of mkDerivation but did not seem to work.

let
  myPackage = callPackage ./myPackage.nix {};
in
  stdenv.mkDerivation {
    name = myPackage.name;

    buildInputs = [ myPackage hlint hasktags ];
}

Beside nix-build stop working, it also drop me in the shell with executable of myPackage but without myPackage's env.

I know this because ghc is not avaliable while it exists in myPackage's env when using default.nix above.

How can I add those tools to env generated from cabal2nix ?

like image 886
wizzup Avatar asked Dec 09 '17 13:12

wizzup


1 Answers

The nix-shell commands builds all dependencies of a project, sets all environment variables to their respective derivation attribute values and sources (bash) $stdenv/setup. For more details, see the Nix manual about nix-shell.

So in your last example, if you run echo $buildInputs you'll see your built package as a build input. So that works, but it's not what you want.

Instead, you need to reuse the Haskell-specific environment derivation, myPackage.env. This dummy derivation for nix-shell has a GHC that is set up to discover only your dependencies etc.

pkgs.lib.overrideDerivation myPackage.env (old: {
    buildInputs = old.buildInputs ++ [ pkgs.haskellPackages.hlint ];
})

Unsolicited advice ;)

In my projects, I use a shell.nix file for this. This also lets me avoid the lib.inNixShell value that breaks referential transparency.

If your project consists of more than a Haskell package, I recommend writing an overlay. It will make your project much more coherent.

shell.nix

# This imports the project + overlay. The overlay takes care of
# adding `myPackage` to `haskellPackages`, to make it available
# throughout the project.
attrs@{...}:
let pkgs = (import ../nix attrs);

# Adapt myPackage.env
in pkgs.lib.overrideDerivation pkgs.haskellPackages.myPackage.env (old: {
    buildInputs = old.buildInputs ++ [ pkgs.haskellPackages.hlint ];
})

For an example of an overlay, see zimbatm's todomvc-nix.

like image 97
Robert Hensing Avatar answered Oct 17 '22 09:10

Robert Hensing