Custom packages with NixOS
Building a simple C daemon with Nix, adding it into an existing NixOS configuration without modifying nixpkgs, and then wiring the daemon up to systemd.
The daemon here isn't too noteworthy, it's a mashup of OSC and Lua as a simple remote control. I've called it oschkd
. It's written in C and builds with make
, provided that pkgconfig, liblo, and Lua 5.1 are available.
To build with Nix we can add a default.nix
to the project root with a somewhat standard definition (adjust accordingly):
{ pkgs, lib, stdenv }:
stdenv.mkDerivation {
meta = with pkgs.lib; {
description = "OSC Hotkey Daemon";
homepage = "https://demonastery.org";
license = licenses.gpl3Plus;
};
pname = "oschkd";
version = "git";
buildInputs = with pkgs; [
pkgconfig
liblo
lua51Packages.lua
];
doCheck = true;
src = ./.;
installPhase = ''
mkdir -p $out/bin
cp main $out/bin/oschkd
'';
}
This is enough of a definition to build the C application and link with the necessary libraries.
What wasn't obvious to me was how to actually build this with nix-build
. Running what I hoped might work results in an error:
$ nix-build .
error: cannot evaluate a function that has an argument without a value ('pkgs')
It seems that most people call nix-build
with a variation of this instead:
nix-build -E "with import <nixpkgs> {}; callPackage ./default.nix {}"
This should successfully build the application, leaving a result
symlink in the current directory, and within it you'll find anything that was copied to $out
within the installPhase
section.
From here, adding it to your system is straightforward. I recommend adding an overlay, in your /etc/nixos/configuration.nix
:
nixpkgs.overlays = [
(
self: super:
{
oschkd = super.callPackage /home/path/to/src/oschkd {}; # path containing default.nix
}
)
];
With an overlay, you'll be able to access oschkd
through pkgs
as usual, for example to make it available globally to your system:
environment.systemPackages = with pkgs; [
...
oschkd
];
And/or use it within other Nix expressions, for example adding a systemd user service:
systemd.user.services.oschkd = {
enable = true;
description = "OSC Hotkey Daemon";
# Open up PATH to daemon for launching applications
# NOTE "/bin" is appended to each
path = [ "/home/user" "/run/current-system/sw" ];
serviceConfig = {
ExecStart = "${pkgs.oschkd}/bin/oschkd 9777 /home/user/.config/oschkd.lua";
KillMode = "process";
StandardOutput = "null"; # don't catch output from launched stuff
};
wantedBy = [ "graphical-session.target" ];
};
And that's it, just a nixos-rebuild switch
away.