Using an overlay in the output overlay of a flake and 1000 instances of nixpkgs

Hi there,

I have a simple piece of rust code that I want to write a flake for. The flake contains three interesting outputs: a devShell, a package and an overlay containing said package. My project is very standard, built using the rustPlatform.buildRustPackage function, but I want to use the excellent oxalica/rust-overlay to have more control over the version of rustc and cargo that are used to develop and build my package (for the sake of readability, here we will assume the latest stable).

I am trying to follow the advice from 1000 instance of nixpkgs and avoid creating a new instance of nixpkgs when used as a dependency (I have no such qualms in e.g. the devShell).

This has brought me to write the following code for the overlay (full flake code at the end of the post):

{
  overlay = final: prev: with final;
    let pkgs = prev.appendOverlays [ (import rust-overlay) ];
    in {
      hello-world =
        (prev.makeRustPlatform {
          cargo = pkgs.rust-bin.stable.latest.minimal;
          rustc = pkgs.rust-bin.stable.latest.minimal;
        }).buildRustPackage {
          inherit name version;
          cargoLock.lockFile = ./Cargo.lock;
          buildInputs = [ openssl ];
          nativeBuildInputs = [ pkg-config ];
        };
    };

I have also read this discourse thread, which points out that, regarding the appendOverlays function, the nixpkgs manual states that “it is often preferable to avoid these functions, because they recompute the Nixpkgs fixpoint, which is somewhat expensive to do.”.

This leaves me a bit stymied as to the proper way to go forward: I would like to write a flake that exposes my application to other users through an overlay and as a package, using the oxalica/rust-overlay to control the rust toolchain, and without neither importing nixpkgs or using appendOverlays. With my current nix{,pkgs} knowledge, this seems impossible.

  1. Would the problem be solved if there was a non-overlay way of controlling the rust toolchain (say foo-project), similar to oxalica’s work but where I could write something like foo-project.packages.rust-bin.stable.latest... ? Does such a project exist ?

  2. Currently, I write the code building the package in the overlay and then use the following line for exposing a package:

packages = forAllSystems (pkgs: pkgs.lib.getAttrs [ "hello-world" ] pkgs);

where forAllSystems (also used in the devShells definition) is defined as:

let forAllSystems = f: nixpkgs.lib.genAttrs (import systems) (
  system: f (
    import nixpkgs {
      inherit system;
      overlays = [ self.overlay (import rust-overlay) ];
    }));
in ....

would abandoning the idea of providing users with an overlay and directly writing the package here help in anyway ? I don’t see how I could avoid creating an instance of nixpkgs, since I need to apply the rust-overlay anyway, but maybe there is something I haven’t thought of ?

Thank you for any help or insights on the leanest way to provide a flake for consumers of my application :slight_smile:

Yep, there’s the community project fenix these days, which more or less supersedes oxalica’s rust-overlay: GitHub - nix-community/fenix: Rust toolchains and rust-analyzer nightly for Nix [maintainer=@figsoda]

Overlays don’t make sense in the flake world, flakes are simply a different approach to compose dependencies. Flake-parts fulfill the same niche as overlays here, but you don’t need it for this simple of a project.

Flakes do have their own issue that you need to control the follows, though.