Posted
in category nixos
on 2017-06-05
Table of Contents
Expectations
Not long passed since I first started using Nix and NixOS, that I realized that I would like to have my haskell development to be better integrated with it. I myself is a Vim user (even though I do try Emacs/Spacemacs from time to time) and as such not so much spoiled with lots and lots of tools available. But what I had I would like to be able to reliably use in my new OS.
Here is a very short list of tools that I need to be able to produce code in a more or less distruction free mode in Haskell with Vim:
- Ghc-mod– backend program to enrich Haskell programming in editors
- HLint– tool for suggesting possible improvements to Haskell code
- HIndent– Haskell pretty printer
- Hoogle– Haskell API search engine
Regardless of a specific OS I was using I always installed these packages globally. Such a global state quickly grows to be inconvenient. Every time I need another version of
ghc-mod
I have to re-install it thus breaking old setup. Same applies to some other packages too.
Nix-shell
nix-shell
is a tool that starts an interactive shell based on a Nix expression. What is so good about this tool (not to say Nix package manager and a functional language, NixOS, etc.) is that it will bring all the build/runtime dependencies to live for this project to properly build and run. Nix package manager will also ensure that these packages will not be globally installed for the whole system (like it would be anywhere else), but only when I will need it. So, it sounds like what I need to make my Haskell projects build.
Let’s see how we can get going with literally any cabal-based Haskell project. First, we will need to come up with a Nix expression that will describe a project. Expression itself might look something like this:
I will not go into details of Nix language here. The only thing you should be able to notice rather soon is that this expression correlates with what is there in my cabal file. So, you can guess that it is using amqp
, network
and text
packages, that its version is 0.1.0.0
and its name is hs-amqpbus
.
NixOS developers came up with a very handy tool that will let us parse our cabal file and generate exact equivalent in Nix. It is called cabal2nix
and here is how you might want to generate your expression:
Basically, this will produce shell.nix
file that is by default used by nix-shell
. Now let’s start nix-shell
. You can observe that it fetches and installs all required packages. Once the process completes you will be left inside a new bash shell where you can proceed with building and running your application:
nix-shell
brings all necessary dependencies you might ever need to be able to develop, test and execute your application. Let’s now see how we can make sure that developer tools like ghc-mod
, hindent
, hlint
are available as part of nix-shell
. For that we will have to modify generated shell.nix
slightly:
On line 7
notice additional arguments supplied to f
function: ghc-mod
, hindent
and hlint
. These arguments are then used in buildDepends
attribute of our derivation (i.e. expression, describing our project) on line 17
.
That is pretty much all, just exit your shell (if you happened to be in nix-shell
already) and enter it again – this time you should notice more packages to be installed. Once process completes you can start your best friend - Vim (that hopefully has all you need to get it integrated with ghc-mod
, etc.) and that should have access to all the build tools we specified earlier.
If something does not tick in your Vim, just make sure you have built your project with
cabal build
insidenix-shell
.
Nix-build & Nix-env
Once the development process is done and you no longer need nix-shell
you can build and install your project into Nix store. Here is how you can do this:
If build process completes successfully you should be able to find ./result
symlink in the root of your project (that is a root that ensures that garbage collector in NixOS does not clean all dependencies of your project while you still need them). One last step is to be able to install a project that we just built:
That will register your project as installed in NixOS, and even if you will instruct nix manager to collect garbage, your new binaries will still be there available to you.
Great isolation and reproducibility
Nix is a great package manager with very simple idea - keeping side-effects under control. With Nix you can forget about DLL-hell! It is very much possible to work on the same system on several different projects that require incompatible set of dependencies. Nix’s system of tagging packages with SHA hashes ensures 100% reproducibility - in case any part of your package and/or its dependencies change, hash code changes, resulting in a completely different package.
There is way more to say about Nix and NixOS! One thing I would like to mention though is that Nix is the kind of technology that big enterprises call desruptive in a sense that they have to encompass it.