look around

For the last few weeks I’ve been playing a bit with Nx - the new library for Numeric computation in Elixir. This post is about how I got it running on Elixir 1.12 using niv.

Nx is still offered as a developer build and because of that it ends up having somewhat stringent requirements, in particular the latest version released a few days ago requires the most recent Erlang and Elixir.

The nix community does a great job at keeping the nixpkgs-unstable channel up to date but Elixir 12 was not available yet. Nudged by my friend Ben I decided to see what it would take to rely on community supported packages.

Finding an up-to-date Elixir derivation

To start, I did some googling. I looked for a community repository that offered up to date derivations for Elixir packages.

nix-beam is exactly what I needed. It exposes several derivations for BEAM (Erlang virtual machine).

To list them I ran the following command, as instructed in the README of nix-beam.

$ nix-env -qaP -f https://github.com/jechol/nix-beam/archive/master.tar.gz

pkg.v23_3.elixir.v1_10_4  elixir-1.10.4_erlang-23.3
pkg.v23_3.elixir.v1_11_4  elixir-1.11.4_erlang-23.3
pkg.v23_3.elixir.v1_12_0  elixir-1.12.0_erlang-23.3
pkg.v24_0.elixir.v1_12_0  elixir-1.12.0_erlang-24.0
erlang.v23_3              erlang-23.3
erlang.v24_0              erlang-24.0
pkg.v23_3.rebar3          rebar3-3.15.1_erlang-23.3
pkg.v24_0.rebar3          rebar3-3.15.1_erlang-24.0

Using niv to install Elixir

I then had to add nix-beam as a source of derivations for my nix-shell. In most of my nix-shell configurations I use niv. niv allows me to “pin” the version of nixpkgs and also makes it easy to add other external dependencies.

$ nix-shell -p niv --run "niv init"
$ nix-shell -p niv --run "niv add jechol/nix-beam"

note that by default niv init will track the current nixpkgs-stable

Then I changed my shell.nix to use the package sources generated by niv.

# shell.nix

{ sources ? import ./nix/sources.nix }:
let

  pkgs = import sources.nixpkgs {  };
  beam = import sources.nix-beam { };

  inputs = [
  	...
  	pkgs.inotify-tools # example of nixpkgs package
    beam.pkg.v24_0.elixir.v1_12_0 # package from the nix-beam repository
  ];
in 
  pkgs.mkShell {
    buildInputs = inputs;
  }

Add caching with Cachix

When I ran nix-shell I noticed that after downloading some pre-built derivations a compilation process started. My laptop was about to build Erlang from source!

This is because packages from external sources are not part of the nixpkgs cache, nix-beam only contains the derivation definition after all.

Thankfully the author of nix-beam provides a hosted cache using cachix.

To use it and save a lot of compilation time first I had to install cachix:

$ nix-env -iA cachix -f https://cachix.org/api/v1/install

and then add the provided cache for nix-beam

$ cachix use jechol

Then, I was able to run nix-shell again and no compilation was required!

Note: if you use NixOS you might need to add your user as a trustedUser, that is required for the cachix use part to work.

Conclusion

I hope this post helps you when you find yourself needing a dependency (Elixir or not) that is not available in the main package tree.

Notes:

Funny enough, the nixpkgs Pull Request mentioned at the beginning of this post was merged a few hours after I solved the issue and Elixir 12 is now in the nixpkgs-unstable channel. Because of that, a simpler solution would now be to add a niv source to track unstable and install Elixir using that source.

Also of note, most of the community maintained derivations do not offer caches in cachix but often they also don’t require a big build phase as the ones I was installing in this case.