Compile haskell file

I want to add XMonad.Hooks.ServerMode to my system to interact with xmonad server mode. Here is the custom package:

let xmonadc = with pkgs; stdenv.mkDerivation rec {
  name = "xmonadc-1.0.0";
  src = ../../config/xmonad/xmonadc.hs;
  dontUnpack = true;
  buildInputs = [ ghc xorg.libX11 ];
  buildPhase = ''
    ghc -dynamic ${src}
  '';
  installPhase = ''
    mkdir -p $(out)/bin
    cp xmonodc $(out)/bin
  '';
};

xmonadc.hs contains code of xmonad client from XMonad.Hooks.ServerMode
The issue I’m facing is

@nix { "action": "setPhase", "phase": "patchPhase" }
patching sources
@nix { "action": "setPhase", "phase": "configurePhase" }
configuring
no configure script, doing nothing
@nix { "action": "setPhase", "phase": "buildPhase" }
building
[1 of 1] Compiling Main             ( /nix/store/9y7d11y9chqby1zvh803y0jzynyvc1xv-xmonadc.hs, /nix/store/9y7d11y9chqby1zvh803y0jzynyvc1xv-xmonadc.o )

/nix/store/9y7d11y9chqby1zvh803y0jzynyvc1xv-xmonadc.hs:2:1: error:
    Could not find module `Graphics.X11.Xlib'
    Use -v (or `:set -v` in ghci) to see a list of the files searched for.
  |
2 | import Graphics.X11.Xlib
  | ^^^^^^^^^^^^^^^^^^^^^^^^

/nix/store/9y7d11y9chqby1zvh803y0jzynyvc1xv-xmonadc.hs:3:1: error:
    Could not find module `Graphics.X11.Xlib.Extras'
    Use -v (or `:set -v` in ghci) to see a list of the files searched for.
  |
3 | import Graphics.X11.Xlib.Extras
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

xmonad and contrib are installed with home manager:

  xsession = {
    enable = true;
    windowManager.xmonad = {
      enable = true;
      enableContribAndExtras = true;
      config = ../../config/xmonad/xmonad.hs;
    };
  };

In NixOS and nixpkgs we don’t have a concept of globally installed dependencies, so we need to tell GHC explicitly where to find its dependencies. There is a function in nixpkgs dedicated to that:

let
  ghcWithXMonad = ghc.withPackages (hpkgs: [
    hpkgs.xmonad-contrib
    hpkgs.X11
    # … any other packages you need
  ]);
in

# … here you can use ghcWithXMonad in your derivation

This should also allow you to drop xorg.libX11 from buildInputs. If you want to build a single file derivation you could also make use of pkgs.writers (untested of course since I don’t have your code):

pkgs.writers.writeHaskellBin "xmonadc" {
  libraries = [ haskellPackages.xmonad-contrib haskellPackages.X11 ];
} (builtins.readFile ../../config/xmonad/xmonadc.hs)

writeHaskellBin expects the haskell source as a string (which is useful if you want to have a small Haskell program defined inline in a nix file). We can please it by just using readFile in your case.

PS: Another comment I have on your original derivation is that ghc belongs in nativeBuildInputs which is used for dependencies that need to be executed at build time. buildInputs is for libraries etc. which need to be compiled for the host system (that is where the executable will run). Separating this properly even if there’s no difference between host and build system is not only good practice, but makes cross compiling if you ever want to much easier.

2 Likes

Thank you for the solution, adding

pkgs.writers.writeHaskellBin "xmonadc" {
  libraries = [ haskellPackages.xmonad-contrib haskellPackages.X11 ];
} (builtins.readFile ../../config/xmonad/xmonadc.hs)

is really a great way to write small haskell programs.
and yes, I was a bit confused about buildInputs and nativeBuildInputs, thank you for the clarification.

Edit: I cannot find the button to mark you answer as a solution. I’m not sure if it’s a problem with the nix discourse or some design change here. Thank you you help tho.

2 Likes

For reference, this is the manual section documenting dependency specifications which is a bit more complicated than necessary maybe.

1 Like