Haskell project with private dependency that should come from another haskellPackage causes `Encountered missing or private dependencies:`

I created a simple flake to be able to run specifically version 1.22.2 of hledger.

$ cat flake.nix 
{
  description = "Hledger 1.22.2  (https://github.com/simonmichael/hledger)";

  # Commit containing side-by-side 'hledger' (1.21) and 'hledger_1_22_2 (1.22.2)
  inputs.nixpkgs.url = "github:nixos/nixpkgs/f8f124009497b3f9908f395d2533a990feee1de8";

  # https://zero-to-nix.com/concepts/flakes
  outputs = { self, nixpkgs }: let

    # Declare the system
    system = "x86_64-linux";

  in {
    packages.${system}.default = nixpkgs.legacyPackages.${system}.haskellPackages.hledger_1_22_2;
    defaultPackage.${system} = self.packages.${system}.default;
  };
}

The nix build command fails with

Setup: Encountered missing or private dependencies:
hledger-lib >=1.22.2 && <1.23

The nix commit in question contains two sets of hledger package groups

$ grep -E 'hledger("|_|-lib).*callPackage' nixpkgs-f8f124009497b3f9908f395d2533a990feee1de8/pkgs/development/haskell-modules/hackage-packages.nix 
  "hledger" = callPackage
  "hledger_1_22_2" = callPackage
  "hledger-lib" = callPackage
  "hledger-lib_1_22_2" = callPackage

I successfully use hledger_1_22_2 as default output package but I also need to have nix build use hledger-lib_1_22_2 and not hledger-lib (1.21). It feels like I should be able to tell nix build that hledger-lib should come from haskellPackages.hledger-lib_1_22_2, but how? I’m not a regular nix user, only started using it recently for the few commands that I need to compile in a reproducible manner.

I’ve heard overlays are the future, and I played around a bit, but feel out of my league.

Any advice appreciated, thanks

I managed to achieve what I wanted with an overlay (or what I think is an overlay)

{
  description = "Hledger 1.22.2  (https://github.com/simonmichael/hledger)";

  # Commit contains side-by-side 'hledger*' (1.21) and 'hledger_1_22_2*' packages (1.22.2)
  inputs.nixpkgs.url = "github:nixos/nixpkgs/f8f124009497b3f9908f395d2533a990feee1de8";

  # https://zero-to-nix.com/concepts/flakes
  outputs = { self, nixpkgs }:

  let
    # Declare the system
    system = "x86_64-linux";

    # Redirect hledger here
    redirectedHaskellPackages = nixpkgs.legacyPackages.${system}.haskellPackages.extend (final: prev: {
      hledger = prev.hledger_1_22_2;
      hledger-lib = prev.hledger-lib_1_22_2;
    });

  in {
    packages.${system}.default = redirectedHaskellPackages.hledger;
    defaultPackage.${system} = self.packages.${system}.default;
  };
}

The build completes and I get the hledger version I wanted

$ result/bin/hledger --version
hledger 1.22.2, linux-x86_64

Is this the canonical way to do this, or can it be simplified?

The fact that there is final: and prev: in the overlay, but I never needed to use final. is weird.
What’s up with what?

1 Like

Overlays are described here. You probably should be using final for aliasing in your example, although it doesn’t make a difference in your example.

prev is the previous version of the package set your overlay receives. prev is to be used whenever you modify a package, i.e. foo = prev.foo.override { … } will never cause an infinite recursion. final is the self reference of the new package set you are going to return from the overlay, so it should be used for dependencies among packages etc.

Where can I find more information about the difference between .extend v .override?

extend doesn’t exist for derivations. .override has its own section in the nixpkgs manual, as do Haskell specific overridding techniques (i.e. overrideCabal).