Nix Developer Shells · Workshop Lektion 9 / Eigene Pakete

Eigene Pakete I: mkDerivation

Vom Tool-Nutzer zum Tool-Bauer. Die Phasen, aus denen jedes Nix-Paket entsteht.

Warum das zählt
Bisher hast du fertige Pakete benutzt. Jetzt baust du eines selbst – die zweite Hälfte deiner Mission. Heute das allgemeine Werkzeug stdenv.mkDerivation und seine Build-Phasen; in Lektion 10 dann der bequeme Go-Builder für unsere toolbox-CLI.

mkDerivation ist auch nur eine Funktion

stdenv.mkDerivation nimmt – du ahnst es (Lektion 3) – ein Set und erzeugt daraus eine Derivation, die ein Programm baut. Das Minimalgerüst:

pkgs.stdenv.mkDerivation {
  pname   = "hello-toolbox";
  version = "1.0";

  src = ./.;          # Quelle: dieses Verzeichnis (ein Pfad, Lektion 2!)

  installPhase = ''
    mkdir -p $out/bin
    cp hello.sh $out/bin/hello-toolbox
    chmod +x $out/bin/hello-toolbox
  '';
}

Die Build-Phasen

Nix baut ein Paket in einer festen Reihenfolge von Phasen. Du überschreibst nur die, die du brauchst – der Rest hat sinnvolle Defaults:

unpack

src auspacken

patch

Patches

build

kompilieren

install

nach $out
$out ist der Ziel-Pfad im Store. Was dort landet, ist dein Paket.

nativeBuildInputs: Werkzeuge zur Bauzeit

Brauchst du beim Bauen Tools (z. B. make, pkg-config), kommen sie in nativeBuildInputs – jetzt zahlt sich Lektion 7 aus:

  nativeBuildInputs = [ pkgs.makeWrapper ];
  buildInputs       = [ pkgs.openssl ];      # Libraries zum Linken

Quellen & Hashes

Holst du die Quelle aus dem Netz (statt aus ./.), verlangt Nix einen Hash – die Garantie, dass alle bit-genau dieselbe Quelle bekommen:

  src = pkgs.fetchFromGitHub {
    owner  = "you";
    repo   = "toolbox";
    rev    = "v1.0";
    hash   = "sha256-AAAA…";   # Inhalts-Prüfsumme der Quelle
  };
Der Hash-Trick Du kennst den Hash anfangs nicht. Setze hash = pkgs.lib.fakeHash; (lauter Nullen), baue einmal – Nix bricht ab und nennt dir den echten Hash in der Fehlermeldung. Den trägst du ein, fertig.
Dein Win Du hast den Bogen geschlagen: Du verstehst jetzt, dass jedes Paket in Nixpkgs genau so gebaut wird – src, Phasen, $out. Damit kannst du jedes Paket lesen und einfache selbst schreiben.

Besonderheiten & Stolperfallen

Der Build hat kein Internet Build-Phasen laufen sandboxed, ohne Netzwerk. Genau deshalb müssen alle Quellen über src/fetch* mit Hash deklariert sein. Ein curl in der buildPhase schlägt fehl – das ist Absicht, nicht ein Bug.
Nur $out zählt Was du nicht nach $out kopierst, existiert nach dem Build nicht. Vergessene mkdir -p $out/bin oder ein Tippfehler im Zielpfad ist die häufigste Ursache für „Paket gebaut, aber Befehl fehlt".
Für Skripte gibt es Abkürzungen Ein einzelnes Shell-Skript verpackt pkgs.writeShellApplication { name = …; text = …; } in einer Zeile – inklusive PATH-Wrapping. mkDerivation ist der allgemeine Weg darunter.

Kurz prüfen (aus dem Kopf)

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

Was bedeutet die Variable $out in einer Derivation?

Warum verlangt fetchFromGitHub einen Hash?

Warum schlägt ein curl in der buildPhase fehl?

Übung für Teilnehmende

Ziel: Ein winziges Shell-Tool als Nix-Paket bauen.

  1. Lege hello.sh an: #!/bin/sh + echo "hallo aus toolbox".
  2. Schreibe eine tool.nix mit stdenv.mkDerivation, dontUnpack = true; und einer installPhase, die das Skript nach $out/bin/hello-toolbox kopiert.
  3. Baue es: nix-build tool.nix (oder via Flake, Lektion 11) und führe ./result/bin/hello-toolbox aus.

Tipp: src = ./.; nimmt das aktuelle Verzeichnis als Quelle – inklusive deiner hello.sh.

Lösung anzeigen
# tool.nix
let pkgs = import <nixpkgs> {}; in
pkgs.stdenv.mkDerivation {
  pname = "hello-toolbox"; version = "1.0";
  src = ./.; dontUnpack = true;
  installPhase = ''
    mkdir -p $out/bin
    cp $src/hello.sh $out/bin/hello-toolbox
    chmod +x $out/bin/hello-toolbox
  '';
}
# $ nix-build tool.nix && ./result/bin/hello-toolbox → "hallo aus toolbox"

Du hast gerade dein erstes Nix-Paket gebaut. In Lektion 10 machen wir daraus ein echtes Go-CLI.

Primärquelle zum Lesen nixpkgs Manual – stdenv & Phasen. Die maßgebliche Erklärung der Build-Phasen. Lies „Phases" und „Attributes" – kompakt und definitiv.
Ich bin dein Teacher. Dein Build findet eine Datei nicht, oder der Hash will nicht passen? Schick mir tool.nix und die Fehlermeldung – Hash-Fehler löst man in 30 Sekunden.
← Lektion 8 · Lock-Files Lektion 10 · Eigene Pakete II →
Als Nächstes: Lektion 10 – Eigene Pakete II (buildGoModule & Co.)