Search code examples
haskellcabalhaskell-stacknix

How to set cabal flag from shell.nix for stack project?


By default I build my project without nix, and executable is linked statically. But when building with nix, I want to link it dynamically instead. So I added a switch to myproj.cabal:

flag dynamic
  description: Build only dynamic binaries
  default: False

executable RunMe
  ghc-options:         -O2 -Wall
  if !flag(dynamic)
    ghc-options: -optl-static -static

Now I can build the project with

stack --nix --nix-packages=zlib install --flag myproj:dynamic

To avoid passing command line options every time, I created shell.nix:

{ghc}:
with (import <nixpkgs> {});
haskell.lib.buildStackProject {
  inherit ghc;
  name = "myproj";
  buildInputs = [ zlib ];
}

Now, I don't know how to pass flag to cabal from nix file. Based on buildStackProject definition, I tried setting buildPhase, e.g.

haskell.lib.buildStackProject {
  ...
  buildPhase = "stack build --flag=myproj:dynamic";
}

but it doesn't seem to change anything. How can I pass the flag to cabal from the nix file?


Solution

  • Unfortunately, the stack nix integration is rather backwards. It doesn't use nix to build your package (despite the very misleadingbuildStackPackage), just to create an environment with GHC and native dependencies. You have to use stack itself to build the project, and since stack will run cabal, it should still work with the flag. The stack nix integration will not generate a .nix file with the dependencies resolved by stack, so you can't build your project with nix-build and there's no point in entering nix-shell. You would have to use a tool like stack2nix or stackage2nix for that.

    So to recap. The shell.nix above looks fine. Add this to your stack.yaml:

    nix:
        shell-file: shell.nix
    

    And build the project with stack:

    stack --nix --flag myproj:dynamic
    

    That should build the project with the flag as usual, but use GHC and zlib from nix.