Nixify Stack project - Nix

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Fintan Halpenny

So I moved to a NixOS machine a while back and I haven't done any Haskell development in it really. But I'm looking to build a Stack project and not sure how to go about things like getting the right GHC version.

Can people point me to some resources for getting up to speed with taking an existing Stack based project and building it using Nix? I'm also just cargo culting Nix still so I really need to get a grip on how to write derivations and all that jazz. I have a shallow understanding of how it all works :)

Torsten Schmits

first of all, there's stack2nix

Generate nix expressions for Haskell projects. Contribute to input-output-hk/stack2nix development by creating an account on GitHub.
Fintan Halpenny

Ya I tried that and it failed to do anything which wasn't inspiring. And then I got the sense it was abandoned for their haskell.nix project

Torsten Schmits

so how customized is your stack config?

Torsten Schmits

and what's your development workflow? ghcid?

Fintan Halpenny

It's the unison project

Fintan Halpenny

So I just wanna stack build to get the executable

Fintan Halpenny

If I learn other stuff along the way then that's a bonus :grinning_face_with_smiling_eyes:

Torsten Schmits

then you basically want to get to the point where you run nix-build -A ghc.unison

Torsten Schmits

so your nix expression needs to choose a ghc from nixpkgs and stuff it with package overrides

Torsten Schmits

you choose a ghc by saying pkgs.haskell.packages.ghc884, choosing the version you want

Torsten Schmits

then you call ghc.override { overrides = myOverrides; }

Torsten Schmits

where myOverrides has the shape finalGhc: previousGhc: { conduit = finalGhc.callCabal2nix "conduit" /home/fintan/conduit; ... }

Torsten Schmits

where finalGhc and previousGhc are ways to say "I want to use whatever is gonna be the override at the end" and "I want to override this"

Fintan Halpenny

Annnd I'm lost a bit :sweat_smile: at a high level I think this makes sense but writing the derivation is still a bit beyond me

Torsten Schmits

and whatever is in that set is used as a package db

Torsten Schmits
{}:
let
  pkgs = import <nixpkgs> {};
  ghc = pkgs.haskell.packages.ghc884.override {
    overrides = finalGhc: previousGhc: {
      unison-core = finalGhc.callCabal2nix "unison-core" ./unison-core {};
   };
};
in {
  inherit ghc;
}
Torsten Schmits

use that as default.nix and run nix-build -A ghc.unison-core

Torsten Schmits

(updated with the correct names)

Fintan Halpenny

Ya was realising it was under unsion-core :smile:

Fintan Halpenny

I'm getting a syntax error on in :thinking:

Torsten Schmits

updated it so that ghc is actually an attribute

Fintan Halpenny

So, now I'm getting error: attribute 'ghc884' missing, at /home/haptop/Developer/unison/default.nix:4:9

Fintan Halpenny

What does your brain say when you see this error? Like I wanna know what steps I should think about when I come across something like this

Torsten Schmits

well, first thought is that I either used the wrong attribute path or that your nixpkgs doesn't have ghc 8.8.4

Fintan Halpenny

Also it seems like the resolver unison uses points to 8.8.3

Fintan Halpenny

Hmmm, but I'm _pretty_ sure I'm using 20.03

Torsten Schmits

well, those are details that aren't necessary to get the derivation working but you can just use 883

Torsten Schmits

so change it to 883 and then try, for example, nix-build -A ghc.aeson

Fintan Halpenny

Which details aren't necessary?

Torsten Schmits

then if it works, just ctrl-c

Fintan Halpenny

It does not :grimacing:

Fintan Halpenny

Still missing the attribute

Torsten Schmits

which compiler version to use. we just want to get the nix expression right, not build successfully :smile:

Fintan Halpenny

Appreciate the help :bow:

Torsten Schmits

try import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/773ef5ae78339db744b917c2b35d28812028bd8c.tar.gz") {}

Fintan Halpenny

Would that go before the let?

Torsten Schmits

(instead of import <nixpkgs>)

Torsten Schmits
{}:
let
  pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/773ef5ae78339db744b917c2b35d28812028bd8c.tar.gz") {};
  ghc = pkgs.haskell.packages.ghc884.override {
    overrides = finalGhc: previousGhc: {
      unison-core = finalGhc.callCabal2nix "unison-core" ./unison-core {};
   };
};
in {
  inherit ghc;
}
Fintan Halpenny

So we're just pinning the packages to that archive entry?

Torsten Schmits

yeah just to be sure nothing in your env is overriding

Fintan Halpenny

There's compiling Haskell at least :sweat_smile:

Torsten Schmits

then you can start trying nix-build -A ghc.unison-core

Fintan Halpenny

That's what I've ran :)

Torsten Schmits

now the stack dep overrides. you'll want to add an attribute for each to your ghc, just like unison-core. then there's multiple variants for adding packages:

Torsten Schmits
strings = finalGhc.callHackage "strings" "1.1" {};

this is the simplest, and requires that this version is in the curated set in nixpkgs

Fintan Halpenny

So I should stop the build?

Torsten Schmits

if not, you'll need callHackageDirect { pkg = "strings"; ver = "1.1"; sha256 = "asdkfjasdkfj"; } where you'll have to either put a wrong sha in there and wait for nix to tell you the right one (do not use the sha of another package, it will use that then) or use nix-prefetch-url with the hackage url

Torsten Schmits

well you can run it till you get an error if you like and hack on the file in the meantime :smile:

Torsten Schmits

but if there's a late version conflict of a very general package, all of its deps will be rebuilt

Torsten Schmits

and the last one would be github deps

Fintan Halpenny

So, these entries go into the override set?

Torsten Schmits
configurator = finalGhc.callCabal2nix "configurator" (pkgs.fetchFromGithub { repo = "unisonweb/configurator"; .. };
Fintan Halpenny

Where did you find strings from? :thinking:

Torsten Schmits

exactly, as attributes just like unison-core

Fintan Halpenny

Ok, I'll have to come back to this later. I should do some work-work :joy: Thanks for getting me going on this @Torsten Schmits :heart:

Torsten Schmits

happy to help :upside_down:

codygman

I use haskell.nix for this, but it has some annoyances

Torsten Schmits

codygman said:

I use haskell.nix for this, but it has some annoyances

what are those?

codygman

If you want to use stack inside of a nix shell that uses Nix installed packages you have to do this and it's brittle when packages changed because stack will try to install them:

https://github.com/codygman/haskell-nix-stack-workflow/tree/e66a50e2be2706724174b2e7d3c5e4a884f42179

Contribute to codygman/haskell-nix-stack-workflow development by creating an account on GitHub.
codygman

Err you probably want master instead of that tree if you try it. Related discussion: https://github.com/input-output-hk/haskell.nix/issues/689#issuecomment-683658719

update the docs with a minimal copy-pastable example for stack (moving extra stuff to "appendix" or something) figure out if we want to work with stack to disable their nix support when i...
Torsten Schmits

why stack inside of nix-shell? we were replacing stack here

codygman

Oh, my mistake. Here I wanted to use stack as a dumb frontend but have nix do the real work. If you think stacks UX is nicer to use or your team does, this is nice.

Why not use stack --nix? To avoid specifying dependencies anywhere but default.nix and package.yaml, work with direnv, and probably other things I forgot.

Torsten Schmits

interesting proposition!

codygman

I've been challenging that proposition by using stack --nix more as of late though. I'm undecided which approach I think is better.

Torsten Schmits

do you have a list of features that have significantly better UX in stack?

codygman

I moved over to cabal by default recently to rediscover those and challenge that view, so not yet.

However these come to mind:

  • stack build --profile
  • stack build --fast
  • hpack maybe but yaml dangerous
  • stack new (I think this might not be true anymore?)
  • stack ghci loading everything by default.. or for some reason cabal doesn't have everything I expect
Torsten Schmits

and haskell.nix doesn't offer adequate replacements?