Nix-shell + overlay + direnv

For a project, I have a shell.nix as follows:

with import <nixpkgs> { };
stdenv.mkDerivation {
  name = "env";

  nativeBuildInputs = [
    wails
  ];

  buildInputs = [
    gcc
    gnumake
    go
    xorg.libX11
    xvfb-run
  ];

  shellHook = ''
    export LD_LIBRARY_PATH="${lib.makeLibraryPath [ xorg.libX11 ]}"
  '';
}

Some times I need to use an overlay for wails while I wait for the latest version to make its way through nixpkgs review and CI/CD. I have a wails-overlay.nix for that:

self: super: {
  wails = super.buildGoModule rec {
    pname = "wails";
    version = "2.0.0-beta.36";

    src = super.fetchFromGitHub {
      owner = "wailsapp";
      repo = "wails";
      rev = "v${version}";
      sha256 = "sha256-uAbVc1UDgSNJwk8R6zXXqZImo6J9TRs3zPNlWelXS/I=";
    } + "/v2";

    vendorSha256 = "sha256-rrwlFZQT7sHhUqtU4UzwEqZbjWd/1fudfj/xdTGFUmQ=";

    proxyVendor = true;

    subPackages = [ "cmd/wails" ];

    # These packages are needed to build wails
    # and will also need to be used when building a wails app.
    nativeBuildInputs = [
      super.pkg-config
      super.makeWrapper
    ];

    # Wails apps are built with Go, so we need to be able to
    # add it in propagatedBuildInputs.
    allowGoReference = true;

    # Following packages are required when wails used as a builder.
    propagatedBuildInputs = [
      super.pkg-config
      super.go
      super.gcc
      super.gtk3
      super.webkitgtk
      super.nodejs
      super.upx
    ];

    ldflags = [
      "-s"
      "-w"
    ];

    # As Wails calls a compiler, certain libraries need to be made available.
    postFixup = ''
      wrapProgram $out/bin/wails \
        --prefix PATH : ${super.lib.makeBinPath [ super.pkg-config super.go super.gcc super.nodejs super.upx ]} \
        --prefix LD_LIBRARY_PATH : ${super.lib.makeLibraryPath [ super.gtk3 super.webkitgtk ]} \
        --set PKG_CONFIG_PATH "$PKG_CONFIG_PATH" \
        --set CGO_LDFLAGS "-L${super.lib.makeLibraryPath [ super.zlib ]}"
    '';

    doCheck = true;

    meta = with super.lib; {
      description = "Build applications using Go + HTML + CSS + JS";
      homepage = "https://wails.io";
      license = licenses.mit;
      maintainers = with maintainers; [ ianmjones ];
      platforms = platforms.linux;
    };
  };
}

I’m struggling to find a way of using that overlay from within that shell.nix. In my machine’s configuration.nix I have the following kind of thing:

nixpkgs.overlays = [
  (import ./wails-overlay.nix)
];

When I try to use any variation of that in the shell.nix I get various errors about converting sets to string, or errors that make it obvious that I can’t specify an overlays attribute (with or without nixpkgs prefix and other stabs in the dark I’ve made).

The goal is to be able to use this with direnv when .envrc simply contains use nix.

The project is also set up to use commands such as nix-shell --pure --run 'make' in CI, and so having the wails-overlay.nix able to be imported via shell.nix will hopefully work there too.

Ideally, once the latest version of wails makes its way into nixpkgs I’d likely disable the overlay until the next time there’s a new version to test and I’d just re-enable the updated overlay in my project.

I’ve seen some posts that mention calling nix-shell with an overlays arg. Is that the only way to use an overlay with nix-shell, or is there a way to include an overlay file in shell.nix?

Have you tried:

with import <nixpkgs> { overlays = [(import ./wails-overlay.nix)]; };
stdenv.mkDerivation {
  name = "env";

  nativeBuildInputs = [
    wails
  ];

  buildInputs = [
    gcc
    gnumake
    go
    xorg.libX11
    xvfb-run
  ];

  shellHook = ''
    export LD_LIBRARY_PATH="${lib.makeLibraryPath [ xorg.libX11 ]}"
  '';
}

import <nixpkgs> is just magic for “go find the copy of nixpkgs that was downloaded by my channel and put whatever is in its default.nix here”. That in turn imports https://github.com/NixOS/nixpkgs/blob/d33eace057c830a5c1b43914d1e4287f7db605bb/pkgs/top-level/impure.nix, which is a function that takes arguments - and you’re calling it with the { }.

The function has a bunch of default args, but you can set them, like the overlays one. It’s worth having a read through the args once in a while.

with finally takes all top-level things in the resulting attrset and puts them in scope.

While I’m at it, using with is often discouraged, especially if you use it at the beginning of a file like here.

1 Like

That works perfectly! :tada:

Thank you very much for the help and additional information, much appreciated.