Nix Developer Shells · Workshop Lektion 11 / Eigene Pakete

Paket in die Dev-Shell

Der Bogen schließt sich: dein selbst gebautes Tool als Output und in der Shell.

Warum das zählt
Jetzt verbinden wir beide Hälften des Kurses: das eigene Paket (L9–10) und die Dev-Shell (L6–7). Am Ende hat dein Flake einen packages.default-Output (per nix run startbar) und stellt dasselbe Tool in der Dev-Shell bereit – die komplette toolbox.

callPackage: Dateien sauber einbinden

In Lektion 10 war toolbox.nix eine Funktion (sie nahm { buildGoModule, ... }). pkgs.callPackage ruft so eine Funktion auf und füllt ihre Argumente automatisch aus pkgs – du musst nichts von Hand durchreichen:

toolbox = pkgs.callPackage ./toolbox.nix {};
# callPackage schaut in pkgs nach buildGoModule, lib, … und reicht sie ein

Das vollständige toolbox-Flake

So sieht die flake.nix aus, wenn beides zusammenkommt:

  outputs = { self, nixpkgs }:
    let
      system  = "x86_64-linux";
      pkgs    = nixpkgs.legacyPackages.${system};
      toolbox = pkgs.callPackage ./toolbox.nix {};     # dein Paket
    in {
      # 1) als baubares/ausführbares Paket:
      packages.${system}.default = toolbox;

      # 2) und gleichzeitig in der Dev-Shell verfügbar:
      devShells.${system}.default = pkgs.mkShell {
        packages = [ pkgs.go pkgs.jq toolbox ];   # ← dein Tool neben den anderen
      };
    };

Damit kannst du:

$ nix build           # baut toolbox → ./result/bin/toolbox
$ nix run             # baut & startet toolbox direkt
$ nix develop         # Shell, in der `toolbox` im PATH liegt

Overlays: pkgs erweitern

Manchmal willst du dein Paket (oder eine gepatchte Version) so einbinden, als wäre es Teil von Nixpkgs – damit andere Pakete es über pkgs.toolbox finden. Das macht ein Overlay:

      pkgs = import nixpkgs {
        inherit system;
        overlays = [
          (final: prev: {
            toolbox = final.callPackage ./toolbox.nix {};
          })
        ];
      };
# jetzt existiert pkgs.toolbox überall im Flake

Ein Overlay ist eine Funktion final: prev: { … }: prev ist das alte pkgs, final das fertige (für gegenseitige Referenzen). Für eine einzelne Dev-Shell reicht oft callPackage ohne Overlay – Overlays glänzen, wenn mehrere Pakete aufeinander aufbauen.

Dein Win Dein Flake ist jetzt komplett: ein eigenes, reproduzierbares Paket – baubar, ausführbar und Teil der Dev-Shell. Das ist die Vollform aus deiner Mission. Was bleibt, ist Komfort (direnv) und das Feinwissen (Lektion 13).

Besonderheiten & Stolperfallen

callPackage vs. direkter Import import ./toolbox.nix liefert nur die Funktion – die Argumente fehlen dann. callPackage ./toolbox.nix {} ruft sie korrekt mit den pkgs-Argumenten auf. „function called without required argument" heißt fast immer: import statt callPackage benutzt.
Overlay nur bei Bedarf Ein Overlay baut pkgs neu auf und kostet Auswertungszeit. Für „ich will mein Tool in einer Shell" ist die lokale let toolbox = … in-Variante schlanker.
nix run braucht $out/bin nix run startet das Programm aus packages.default. Es muss also ein ausführbares Binary in $out/bin liegen – genau das, was die Sprach-Builder automatisch tun.

Kurz prüfen (aus dem Kopf)

Nicht spicken – Abrufen aus dem Gedächtnis ist genau die Übung, die hängen bleibt.

Was leistet pkgs.callPackage ./toolbox.nix {}?

Wie machst du dein Paket in der Dev-Shell verfügbar?

Wann lohnt sich ein Overlay statt callPackage allein?

Übung für Teilnehmende

Ziel: Das toolbox-Paket aus Lektion 10 in dein Flake einhängen.

  1. Binde toolbox = pkgs.callPackage ./toolbox.nix {}; im let deines Flakes ein.
  2. Setze packages.<system>.default = toolbox; und teste nix run.
  3. Füge toolbox zur packages-Liste der Dev-Shell hinzu.
  4. nix develop, dann toolbox direkt aufrufen – es liegt im PATH.

Tipp: git add toolbox.nix nicht vergessen, sonst sieht das Flake die Datei nicht.

Lösung anzeigen
  let
    system  = "x86_64-linux";
    pkgs    = nixpkgs.legacyPackages.${system};
    toolbox = pkgs.callPackage ./toolbox.nix {};
  in {
    packages.${system}.default  = toolbox;
    devShells.${system}.default = pkgs.mkShell {
      packages = [ pkgs.go toolbox ];
    };
  }
# nix run → startet toolbox; nix develop → toolbox im PATH

Glückwunsch: ein vollständiges Flake aus eigenem Paket + reproduzierbarer Dev-Shell.

Primärquelle zum Lesen nixpkgs Manual – callPackage und Overlays. Lies, wie callPackage Argumente auflöst und wie ein Overlay final/prev nutzt.
Ich bin dein Teacher. „function called without required argument"? Das ist der Klassiker – schick mir die Stelle, fast immer fehlt nur callPackage oder ein git add.
← Lektion 10 · Eigene Pakete II Lektion 12 · direnv & Caching →
Als Nächstes: Lektion 12 – direnv & Caching (use flake, Profi-Kniffe)