Recently, some people have asked me how to build PureScript projects with Nix using Psc-Package2Nix. Admittedly, I haven't seriously tried to do this before with PureScript, because I use Nix primarily to prepare and build tooling and set up my environment. However, doing this with information generated from Psc-Package2Nix is fairly straightforward, but does involve writing some Nix.

From the top

So first, we can start from a project with the regular setup:

psc-package.json src/ Main.purs

As usual, psc-package.json will contain normal Psc-Package information:

{ "name" : "purescript-nix-output" , "set" : "psc-0.12.3" , "source" : "https://github.com/purescript/package-sets.git" , "depends" : [ "console" , "prelude" ] }

Then we can use Psc-Package2Nix to generate a Nix expression with our packages.

> psc-package2nix # or pp2n psc-package2nix wrote packages.nix

The packages.nix output looks like this:

{ pkgs ? import < nixpkgs > {} }: let inputs = { "console" = pkgs . stdenv . mkDerivation { name = "console" ; version = "v4.2.0" ; src = pkgs . fetchgit { url = "https://github.com/purescript/purescript-console.git" ; rev = "v4.2.0" ; sha256 = "1b2nykdq1dzaqyra5pi8cvvz4dsbbkg57a2c88yi931ynm19nnw6" ; }; phases = "installPhase" ; installPhase = "ln -s $src $out" ; }; # other packages... }; in { inherit inputs ; set = "psc-0.12.3" ; source = "https://github.com/purescript/package-sets.git" ; }

So we can see that the generated expression has a set ("record") named inputs , where each input contains the dependency that was cloned.

Supplying inputs to PureScript

The PureScript compiler works by simply being passed a bunch of globs for where to find files. This means that if we provide some prefixed globs of "src/**/*.purs" , we can feed the inputs into the compiler to build.

Knowing this, we know we can prepare globs by mapping a function to produce the globs from inputs :

{ pkgs ? import < nixpkgs > {} }: let packages = import ./packages.nix { inherit pkgs ; }; getGlob = pkg : ''" ${ pkg } /src/**/*.purs"'' ; globs = with builtins ; toString ( map getGlob ( attrValues packages . inputs ));

Then we can later call purs with these globs.

Writing the whole derivation

So now we know how to prepare the globs, so all that is left is to provide the PureScript compiler and write our project derivation. The PureScript compiler can be obtained from my Easy-PureScript-Nix project. Then we can call the PureScript compiler in the derivation's install phase and move the output produced into where it needs to go. And so:

{ pkgs ? import < nixpkgs > {} }: let easy-ps = import ( pkgs . fetchFromGitHub { owner = "justinwoo" ; repo = "easy-purescript-nix" ; rev = "d383972c82620a712ead4033db14110497bc2c9c" ; sha256 = "0hj85y3k0awd21j5s82hkskzp4nlzhi0qs4npnv172kaac03x8ms" ; }); packages = import ./packages.nix { inherit pkgs ; }; getGlob = pkg : ''" ${ pkg } /src/**/*.purs"'' ; globs = with builtins ; toString ( map getGlob ( attrValues packages . inputs )); in pkgs . stdenv . mkDerivation { name = "purescript-nix-output-demo" ; src = ./. ; installPhase = '' rm -rf output # ensure we dont use stale output ${ easy-ps . purs } /bin/purs compile ${ globs } "src/**/*.purs" mkdir -p $out mv output $out '' ; }

And this is it. When we run nix-build , we will produce a result symlink where we can see the output, and we can even run the output directly using node:

> node -e "require('./result/output/Main').main()" Hello World

Conclusion

Hopefully this has shown you that building the PureScript part of your project is fairly straightforward if you use a Psc-Package configuration file and use Psc-Package2Nix.

Links