Installing a custom Haskell package on NixOS

I have a utility program written in Haskell. I have successfully built it using nix-build jot.nix. But now I would like to install it in NixOS and have it be available on $PATH.

I have read what the NixOS manual says about custom packages, but I think that example is for an autotools build, and I can’t figure out how to adapt that example to my situation. I think some changes need to be made to jot.nix.

I anticipate that my /etc/nixos/configuration.nix would look like this:

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      /etc/nixos/hardware-configuration.nix
      /etc/nixos/R.nix
      /home/amy/jot/jot.nix
    ];
. . .
  environment.systemPackages = with pkgs; [
    . . .
    jot
    . . .
  ];
. . .

jot.nix:

let
  pkgs = import <nixpkgs> { };
in
  { jot = pkgs.haskellPackages.callPackage ./default.nix { };
  }

And here’s default.nix, which was created using cabal2nix

, time
}:
mkDerivation {
  pname = "Jot";
  version = "1.1";
  src = ./.;
  isLibrary = false;
  isExecutable = true;
  executableHaskellDepends = [
    base cmdargs directory filepath process time
  ];
  license = stdenv.lib.licenses.publicDomain;
}

You’re pretty close.
the short way is to add this to the top of you configuration.nix:

let
    jot = pkgs.haskellPackages.callpackage /home/amy/jot/jot.nix {};
in {
    environment.systemPackages = [ jot ] ++ (with pkgs; [ ... ]);
    #or alternatively (depending on stylistic preference
    environment.systemPackages = with pkgs; [ jot ... ];
    ...
}

the advantage of the former is that it won’t create any conflicts with pkgs.jot in the event that such a package exists. I’m not certain which it would choose in the event of a conflict so I always to the the first way for safety.

Down the line you might consider adding several custom packages, and you might want those packages to be visible to nix-env. To accomplish that you can do:

configuration.nix

let
    mypkgs = import ./mypkgs.nix {};
in {
    nix.nixPath = [
        "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs"
        "nixos-config=/etc/nixos/configuration.nix"
        "mypkgs=/etc/nixos/mypkgs.nix"
        "/nix/var/nix/profiles/per-user/root/channels"
    ];
    environment.systemPackages = (with mypkgs; [ jot foo ]) ++ (with pkgs; [ bar baz ]);
}

mypkgs.nix

{ system ? builtins.currentSystem }:
let
    pkgs = import <nixpkgs> { inherit system; };
    callPackage = pkgs.lib.callPackagesWith (pkgs // self);
    self = {
        # if this is used a dependency for another haskellPackage you will need to redefine "pkgs.haskellPackages.callPackage", but for simple cases this is sufficient.
        jot = pkgs.haskellPackages.callPackage /home/amy/jot/jot.nix { }; 
        foo = callPackage /path/to/foo { }; # where directory foo contains a default.nix
        harold = callPackage /path/to/harold/harold.nix { };
    };
in self

and VOILA nix-env -f '<mypkgs>' -iA mypkgs.jot should install for any users.

2 Likes

I added your first suggestion to the top of my config file, but I’m not sure I did it correctly. I’m getting the following error message. (Note: /etc/nixos/configuration.nix is a symlink to /home/amy/dotWombat/etc/nixos/configuration.nix)

# nixos-rebuild switch
error: syntax error, unexpected ',', expecting '.' or '=', at /home/amy/dotWombat/etc/nixos/configuration.nix:10:9
(use '--show-trace' to show detailed location information)
building Nix...
error: syntax error, unexpected ',', expecting '.' or '=', at /home/amy/dotWombat/etc/nixos/configuration.nix:10:9
(use '--show-trace' to show detailed location information)
building the system configuration...
error: syntax error, unexpected ',', expecting '.' or '=', at /home/amy/dotWombat/etc/nixos/configuration.nix:10:9
(use '--show-trace' to show detailed location information)

/etc/nixos/configuration.nix (aka /home/amy/dotWombat/etc/nixos/configuration.nix)

# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).
let
    jot = pkgs.haskellPackages.callpackage /home/amy/jot/jot.nix {};
in {
    environment.systemPackages = [ jot ] ++ (with pkgs; [ ]);
}

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      /etc/nixos/hardware-configuration.nix
      /etc/nixos/R.nix
    ];

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  # boot.loader.grub.efiSupport = true;
  # boot.loader.grub.efiInstallAsRemovable = true;
  # boot.loader.efi.efiSysMountPoint = "/boot/efi";
  # Define on which hard drive you want to install Grub.
  boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only
  boot.initrd.checkJournalingFS = false;

  # networking.hostName = "nixos"; # Define your hostname.
  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.

  # Configure network proxy if necessary
  # networking.proxy.default = "http://user:password@proxy:port/";
  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

  # Select internationalisation properties.
  i18n = {
    consoleFont = "Lat2-Terminus16";
    consoleKeyMap = "uk";
    defaultLocale = "en_IE.UTF-8";
  };

  # Set your time zone.
  time.timeZone = "Europe/Dublin";

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    auctex
    bash
    binutils-unwrapped
    cabal2nix
    curl
    dmenu2
    docker
    dzen2
    emacs
    firefox
    gcc
    ghc
    ghostscript # for pdf2dsc
    gitAndTools.gitFull
    gnome3.meld
    gnumake
    haskellPackages.cabal-install
    haskellPackages.stylish-haskell
    haskellPackages.X11-xft
    kdeApplications.okular
    libreoffice
    lxqt.qterminal
    gnome3.gnome-disk-utility
    pandoc
    pdfmod
    pkgconfig
    python
    python3
    python36Packages.csvkit
    rEnv
    rsync
    stack
    sxiv
    tectonic
    texstudio
    texlive.combined.scheme-basic
    tree
    unison
    vlc
    x11
    xmonad-with-packages
    xorg.libX11
    xsel
    wget
  ];

  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  # programs.gnupg.agent = { enable = true; enableSSHSupport = true; };

  # List services that you want to enable:

  # Enable the OpenSSH daemon.
  # services.openssh.enable = true;

  # Open ports in the firewall.
  # networking.firewall.allowedTCPPorts = [ ... ];
  # networking.firewall.allowedUDPPorts = [ ... ];
  # Or disable the firewall altogether.
  # networking.firewall.enable = false;

  # Enable CUPS to print documents.
  # services.printing.enable = true;

  # Enable sound.
  sound.enable = true;
  hardware.pulseaudio.enable = true;

  # Enable the X11 windowing system.
#  services.xserver.enable = true;
#  services.xserver.layout = "uk";
  # services.xserver.xkbOptions = "eurosign:e";
  services.xserver = {
    enable = true;
    layout = "ie";
    windowManager.xmonad = {
      enable = true;
      enableContribAndExtras = true;
      extraPackages = haskellPackages: [
        haskellPackages.xmonad
        haskellPackages.xmonad-contrib
        haskellPackages.xmonad-extras
      ];
    };
  };

  # Enable touchpad support.
  # services.xserver.libinput.enable = true;

  # Enable the KDE Desktop Environment.
  services.xserver.displayManager.sddm.enable = true;
  services.xserver.desktopManager.plasma5.enable = true;

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.amy = {
    isNormalUser = true;
    home = "/home/amy";
    description = "Amy de Buitleir";
    extraGroups = [ "wheel" "networkmanager" "vboxsf" ];
    uid = 1000;
  };

  # This value determines the NixOS release with which your system is to be
  # compatible, in order to avoid breaking some software such as database
  # servers. You should change this only after NixOS release notes say you
  # should.
  system.stateVersion = "18.09"; # Did you read the comment?

}

You just concatenated two valid nix expressions. But, like in this case, the result is usually not another valid nix expression. :smiley_cat:

You could format it like this:
https://pastebin.com/raw/v2QfFZip

2 Likes

I think I’m almost there. I have my configuration.nix exactly as given in your pastebin, but I’m getting

# nixos-rebuild switch
building Nix...                                                                  
building the system configuration...                                             
error: attribute 'callpackage' missing, at /home/amy/dotWombat/etc/nixos/configuration.nix:38:11                                                                  
(use '--show-trace' to show detailed location information)

I changed “callpackage” to “callPackage”, and now it works. Thank you Growpotkin and earvstedt for the help.