NixOS Overlay Confusion


#1

I have several single-user systems, and I would like to define a system-level overlay in /etc/nixos/configuration.nix.
I have read the Wiki entry on overlays, and tried to follow the instructions.
However, when I rebuild, I get the error undefined variable 'options'.

Here is my /etc/nixos/configuration.nix.
I added the nix.nixPath definition right before the environment.systemPackages definition.

{ 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";

  nix.nixPath =
    # Prepend default nixPath values.
    options.nix.nixPath.default ++ 
    # Append our nixpkgs-overlays.
    [ "nixpkgs-overlays=/home/amy/nix-overlays/" ]
  ;
  
  environment.systemPackages = let
    jot = pkgs.haskellPackages.callPackage /home/amy/jot/jot.nix {};
  in
    [ jot ] ++ (with pkgs; [
      auctex
      bash
      binutils-unwrapped
      cabal2nix
      curl
      cvc4
      dmenu2
      docker
      dzen2
      # emacs
      (import /home/amy/dotWombat/etc/nixos/emacs.nix { inherit pkgs; })
      firefox
      gcc
      getmail
      ghc
      ghostscript # for pdf2dsc
      gitAndTools.gitFull
      gnome3.dconf
      gnome3.dconf-editor
      gnome3.gnome-disk-utility
      gnome3.meld
      gnumake
      gnupg
      haskellPackages.cabal-install
      haskellPackages.stylish-haskell
#      haskellPackages.liquidhaskell
      haskellPackages.X11-xft
      kdeApplications.okular
      libreoffice
      lxqt.qterminal
      nix-prefetch-git
      pandoc
      pdfmod
      pkgconfig
      python
      python3
      python36Packages.csvkit
      rEnv
      rsync
      stack
      stack2nix
      sxiv
      tectonic
      texstudio
      texlive.combined.scheme-basic
      tree
      unison
      vlc
      x11
      xmonad-with-packages
      xorg.libX11
      xscreensaver
      xsel
      wget
      z3
    ]);

  # 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?

}

And here is the error message that I get.
Line 39:5 is options.nix.nixPath.default ++.

# nixos-rebuild switch --show-trace
error: while evaluating the attribute 'config' at /nix/var/nix/profiles/per-user/root/channels/nixos/nixos/lib/eval-config.nix:57:5:
while evaluating the attribute 'config' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:87:25:
while evaluating 'yieldConfig' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:74:29, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:73:16:
while evaluating 'mergeModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:190:26, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:17:
while evaluating 'mergeModules'' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:194:36, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:191:5:
while evaluating 'flip' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:101:16, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:235:6:
while evaluating 'byName' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:217:25, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:223:21:
while evaluating 'reverseList' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:380:17, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:38:
while evaluating 'filterModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:93:31, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:51:
while evaluating 'closeModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:101:27, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:62:16:
while evaluating anonymous function at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:103:29, called from undefined position:
while evaluating anonymous function at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:103:50, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:103:32:
while evaluating 'unifyModuleSyntax' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:118:34, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:109:11:
while evaluating 'applyIfFunction' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:144:29, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:109:39:
while evaluating 'isFunction' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:288:16, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:144:68:
undefined variable 'options' at /home/amy/dotWombat/etc/nixos/configuration.nix:39:5
building Nix...
error: while evaluating the attribute 'config' at /nix/var/nix/profiles/per-user/root/channels/nixos/nixos/lib/eval-config.nix:57:5:
while evaluating the attribute 'config' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:87:25:
while evaluating 'yieldConfig' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:74:29, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:73:16:
while evaluating 'mergeModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:190:26, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:17:
while evaluating 'mergeModules'' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:194:36, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:191:5:
while evaluating 'flip' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:101:16, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:235:6:
while evaluating 'byName' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:217:25, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:223:21:
while evaluating 'reverseList' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:380:17, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:38:
while evaluating 'filterModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:93:31, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:51:
while evaluating 'closeModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:101:27, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:62:16:
while evaluating anonymous function at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:103:29, called from undefined position:
while evaluating anonymous function at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:103:50, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:103:32:
while evaluating 'unifyModuleSyntax' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:118:34, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:109:11:
while evaluating 'applyIfFunction' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:144:29, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:109:39:
while evaluating 'isFunction' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:288:16, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:144:68:
undefined variable 'options' at /home/amy/dotWombat/etc/nixos/configuration.nix:39:5
building the system configuration...
error: while evaluating the attribute 'config.system.build.toplevel' at /nix/var/nix/profiles/per-user/root/channels/nixos/nixos/lib/eval-config.nix:57:5:
while evaluating the attribute 'config' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:87:25:
while evaluating 'yieldConfig' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:74:29, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:73:16:
while evaluating 'mergeModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:190:26, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:17:
while evaluating 'mergeModules'' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:194:36, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:191:5:
while evaluating 'flip' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:101:16, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:235:6:
while evaluating 'byName' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:217:25, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:223:21:
while evaluating 'reverseList' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:380:17, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:38:
while evaluating 'filterModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:93:31, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:64:51:
while evaluating 'closeModules' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:101:27, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:62:16:
while evaluating anonymous function at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:103:29, called from undefined position:
while evaluating anonymous function at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:103:50, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/lists.nix:103:32:
while evaluating 'unifyModuleSyntax' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:118:34, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:109:11:
while evaluating 'applyIfFunction' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:144:29, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:109:39:
while evaluating 'isFunction' at /nix/var/nix/profiles/per-user/root/channels/nixos/lib/trivial.nix:288:16, called from /nix/var/nix/profiles/per-user/root/channels/nixos/lib/modules.nix:144:68:
undefined variable 'options' at /home/amy/dotWombat/etc/nixos/configuration.nix:39:5

#2

I found a completely different approach that got me a bit further along. At least now nixos-rebuild switch doesn’t complain.

I followed this example.

  1. Create the directory that you want to use for an overlay.

  2. In that overlay directory, create default.nix. I’m not sure if this is needed, since I’m putting each package in a separate directory under my overlays directory.

{
  # Imports `module.nix` if present, which is expected to add to
  # the nixos configuration system.
  imports = (
    if builtins.pathExists(./module.nix) then [ ./module.nix ]
    else []
  );

  # Imports the overlay
  nixpkgs.overlays = [
    (import ./overlays.nix)
  ];
}
  1. Also in that directory, create overlays.nix. Again, I’m not sure if this is needed. Also, I’m not sure what to put in “stuff goes here”.
self: super:

let
  callPackage = self.callPackage;
  mkIf = self.lib.mkIf;
in
{
  # 
  # stuff goes here
  #

}
  1. Modify /etc/nixos/configuration.nix
  imports =
    [ # Include the results of the hardware scan.
      /etc/nixos/hardware-configuration.nix
      . . . 
      /path/to/your/overlay/directory
    ];

#3

With the latter approach, I now have an error when I try to reference a package in my overlay.

$ tree /home/amy/nix-overlays/
/home/amy/nix-overlays/
├── default.nix
├── hello-amy
│   ├── default.nix
│   ├── simple_builder.sh
│   └── simple.c
└── overlays.nix
$ cat /home/amy/nix-overlays/hello-amy/default.nix 
self: super: {
  hello-amy = with super; derivation {
    name = "hello-amy";
    builder = "${bash}/bin/bash";
    args = [ ./simple_builder.sh ];
    inherit gcc coreutils;
    src = ./simple.c;
    system = builtins.currentSystem;
  };
}
$ cat /home/amy/nix-overlays/hello-amy/simple.c 
#include <stdio.h>
void main() {
  puts("Hello, Amy!");
}
$ cat /home/amy/nix-overlays/hello-amy/simple_builder.sh 
export PATH="$coreutils/bin:$gcc/bin"
mkdir $out
gcc -o $out/hello-amy $src

/etc/nixos/configuration.nix looks like this:

  environment.systemPackages = let
    jot = pkgs.haskellPackages.callPackage /home/amy/jot/jot.nix {};
  in
    [ jot ] ++ (with pkgs; [
      . . .
      hello-amy
      . . .
    ]);

And here’s the error:

# nixos-rebuild switch 
building Nix...
building the system configuration...
error: undefined variable 'hello-amy' at /home/amy/dotWombat/etc/nixos/configuration.nix:76:7
(use '--show-trace' to show detailed location information)

#4

Whoops. I’ve edited wiki and added a reference where options comes from. Just add it to top line

{ config, pkgs, options, ... }:

#5

Thank you @danbst. OK, I’m almost there! The only problem now is that NixOS can’t find my hello-amy package.

$ cat /etc/nixos/configuration.nix 
{ config, pkgs, options, ... }:

{
. . .
  nix.nixPath =
    # Prepend default nixPath values.
    options.nix.nixPath.default ++ 
    # Append our nixpkgs-overlays.
    [ "nixpkgs-overlays=/home/amy/nix-overlays/" ]
  ;

  environment.systemPackages = let
    jot = pkgs.haskellPackages.callPackage /home/amy/jot/jot.nix {};
  in
    [ jot ] ++ (with pkgs; [
      . . .
      hello-amy
    ]);
. . .
}

Here’s the error message:

# nixos-rebuild switch 
building Nix...
building the system configuration...
error: undefined variable 'hello-amy' at /home/amy/dotWombat/etc/nixos/configuration.nix:76:7
(use '--show-trace' to show detailed location information)

My overlay directory now looks like this. Note that I removed /home/amy/nix-overlays/default.nix, since the wiki instructions didn’t call for it. I also rewrote overlays.nix according to the wiki.

$ tree -U /home/amy/nix-overlays/
/home/amy/nix-overlays/
├── overlays.nix
└── hello-amy
    ├── simple.c
    ├── default.nix
    └── simple_builder.sh
$ cat /home/amy/nix-overlays/overlays.nix 
self: super:
with super.lib;
let
  # Using the nixos plumbing that's used to evaluate the config...
  eval = import <nixpkgs/nixos/lib/eval-config.nix>;
  # Evaluate the config,
  paths = (eval {modules = [(import <nixos-config>)];})
    # then get the `nixpkgs.overlays` option.
    .config.nixpkgs.overlays
  ;
in
foldl' (flip extends) (_: super) paths self
$ cat /home/amy/nix-overlays/hello-amy/default.nix 
self: super: {
  hello-amy = with super; derivation {
    name = "hello-amy";
    builder = "${bash}/bin/bash";
    args = [ ./simple_builder.sh ];
    inherit gcc coreutils;
    src = ./simple.c;
    system = builtins.currentSystem;
  };
}
$ cat /home/amy/nix-overlays/hello-amy/simple_builder.sh 
export PATH="$coreutils/bin:$gcc/bin"
mkdir $out
gcc -o $out/hello-amy $src
$ cat /home/amy/nix-overlays/hello-amy/simple.c
#include <stdio.h>
void main() {
  puts("Hello, Amy!");
}

#6

Ah. So you’ve left only overlays.nix in overlays directory. It’s code says all it does is appends overlays defined by NixOS option nixpkgs.overlays to your current overlay set. Because you don’t define any other overlays in NixOS, this overlays.nix does effectively nothing for you.

Another thing is that Overlays are not searched recursively. So your nix-overlays/hello-amy/default.nix overlays isn’t found. You should split it into two: derivation and overlay. Overlay should be under nix-overlays/ dir.

nix-overlays/default.nix

self: super: {
  hello-amy = super.callPackage ./hello-amy { };
}

nix-overlays/hello-amy/default.nix

{ gcc, coreutils, bash }:
derivation {
....
}

#7

@danbst Thank you for the explanation; that makes sense. Unfortunately, I’m still getting the same error.

# nixos-rebuild switch 
building Nix...
building the system configuration...
error: undefined variable 'hello-amy' at /home/amy/dotWombat/etc/nixos/configuration.nix:76:7
(use '--show-trace' to show detailed location information)

Here’s my overlay directory now. I believe I correctly made the changes you suggested.

$ tree -U /home/amy/nix-overlays/
/home/amy/nix-overlays/
├── default.nix
├── overlays.nix
└── hello-amy
    ├── simple.c
    ├── default.nix
    └── simple_builder.sh
$ cat /home/amy/nix-overlays/default.nix 
self: super: {
  hello-amy = super.callPackage ./hello-amy { };
}
$ cat /home/amy/nix-overlays/overlays.nix 
self: super:
with super.lib;
let
  # Using the nixos plumbing that's used to evaluate the config...
  eval = import <nixpkgs/nixos/lib/eval-config.nix>;
  # Evaluate the config,
  paths = (eval {modules = [(import <nixos-config>)];})
    # then get the `nixpkgs.overlays` option.
    .config.nixpkgs.overlays
  ;
in
foldl' (flip extends) (_: super) paths self
$ cat /home/amy/nix-overlays/hello-amy/default.nix 
{ gcc, coreutils, bash }:
derivation {
    name = "hello-amy";
    builder = "${bash}/bin/bash";
    args = [ ./simple_builder.sh ];
    inherit gcc coreutils;
    src = ./simple.c;
    system = builtins.currentSystem;
  };
}

#8

I got this result in my test too… Then I looked into source code and found out that nixpkgs-overlays works only for import <nixpkgs> {}, but doesn’t work for pkgs attribute in NixOS. Not sure is this a bug or design…

So you have 2 choices:

  1. Instead of with pkgs; [ hello-amy ] write
with pkgs; [
  ...
  (import <nixpkgs> {}).hello-amy
]

This is ugly, but should work.

  1. Setup overlays declaratively:
  nixpkgs.overlays = [
    (import /home/amy/nix-overlays/default.nix)
  ];

Which should work for your usecase, but still work kinda strange with overlays.nix. I’d better cast @samueldr in this thread for comments.


#9

@danbst Thank you so much for your help. Option 2 worked for me.

It would be nice if overlays worked the same NixOS as they do in plain old Nix. My Nix overlay (on a different machine) doesn’t have a top-level default.nix. I guess that works because Nix does recurse through the directories.

$ tree ~/.config/nixpkgs/overlays
/home/amy/.config/nixpkgs/overlays
└── hello-amy
    ├── default.nix
    ├── simple_builder.sh
    └── simple.c

Anyway, if you or @samueldr would like me to test other configurations, let me know.