Nix Developer Shells · Workshop Lektion 10 / Eigene Pakete

Eigene Pakete II: Sprach-Builder

Niemand schreibt installPhase für Go von Hand. buildGoModule macht es richtig.

Warum das zählt
Für jede gängige Sprache gibt es einen fertigen Builder, der die Phasen aus Lektion 9 korrekt ausfüllt. Heute paketieren wir die toolbox-CLI – ein kleines Go-Programm – mit buildGoModule. Genau dieses Muster brauchst du im Workshop für reale Projekte.

Sprach-Builder statt nackter mkDerivation

buildGoModule, buildPythonApplication, buildNpmPackage, buildRustPackage – alle bauen auf mkDerivation auf, kennen aber die Konventionen ihrer Sprache (wo der Code liegt, wie getestet/gebaut wird). Du füllst nur noch die Metadaten aus.

Die toolbox-CLI mit buildGoModule

Angenommen, toolbox/ enthält ein Go-Modul (go.mod, main.go):

# toolbox.nix
{ buildGoModule, ... }:

buildGoModule {
  pname      = "toolbox";
  version    = "0.1.0";
  src        = ./.;                 # das Go-Projekt
  vendorHash = "sha256-AAAA…";     # Hash über alle Go-Dependencies
}

Das ist die ganze Paket-Definition. buildGoModule kompiliert mit der richtigen Go-Version, lädt die Module reproduzierbar und installiert die Binaries nach $out/bin.

Der vendorHash

Der entscheidende neue Begriff. Go lädt Dependencies aus dem Netz – das verträgt sich nicht mit der netzlosen Build-Sandbox (Lektion 9). buildGoModule löst das mit einem Fixed-Output: Es lädt alle Module einmal und prüft sie gegen vendorHash. So bleiben auch die Dependencies reproduzierbar.

Hash herausfinden – wie in Lektion 9 Setze vendorHash = pkgs.lib.fakeHash;, baue einmal, lies den echten Hash aus der Fehlermeldung, trag ihn ein. Hat ein Projekt gar keine Dependencies, nutze vendorHash = null;.

Andere Sprachen – dasselbe Muster

# Python:
buildPythonApplication { pname = …; version = …; src = ./.; };

# Rust:
rustPlatform.buildRustPackage { pname = …; cargoHash = "sha256-…"; };

# Node:
buildNpmPackage { pname = …; npmDepsHash = "sha256-…"; };

Überall dasselbe Prinzip: pname/version/src plus ein Dependency-Hash. Wer einen Builder kann, kann alle.

Dein Win Du kannst jetzt ein reales Programm reproduzierbar paketieren – mit ein paar Zeilen, nicht mit einem Build-Skript. Damit ist die toolbox-CLI ein echtes Nix-Paket. In Lektion 11 hängen wir es in die Dev-Shell und machen es per nix run ausführbar.

Besonderheiten & Stolperfallen

vendorHash ändert sich mit den Dependencies Jede Änderung an go.mod/go.sum ändert den vendorHash. Der Build bricht dann mit „hash mismatch" ab und nennt den neuen Hash – eintragen, fertig. Das ist ein Feature, kein Fehler: Es zwingt dich, Dependency-Änderungen bewusst nachzuziehen.
Zwei Hashes nicht verwechseln src-Hash (Lektion 9) sichert deinen Quellcode; vendorHash sichert die Dependencies. Bei src = ./.; entfällt der src-Hash – der vendorHash bleibt aber nötig.
Den richtigen Builder finden Welcher Builder zu welcher Sprache gehört, steht im nixpkgs-Manual unter „Languages and frameworks". Für Go ist es buildGoModule, für ältere/GOPATH-Projekte buildGoPackage (selten).

Kurz prüfen (aus dem Kopf)

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

Wozu dient der vendorHash bei buildGoModule?

Wie findest du einen unbekannten vendorHash heraus?

Was haben buildGoModule und buildNpmPackage gemeinsam?

Übung für Teilnehmende

Ziel: Ein minimales Go-CLI mit buildGoModule paketieren.

  1. Lege ein winziges Go-Programm an (go mod init toolbox + ein main.go, das etwas ausgibt).
  2. Schreibe toolbox.nix mit buildGoModule, src = ./.; und vendorHash = pkgs.lib.fakeHash;.
  3. Baue einmal – lies den echten vendorHash aus dem Fehler und trag ihn ein (oder null, wenn keine Deps).
  4. Baue erneut und führe ./result/bin/toolbox aus.

Tipp: Ohne externe Dependencies ist vendorHash = null; der schnellste Weg.

Lösung anzeigen
# toolbox.nix (eigenständig baubar)
let pkgs = import <nixpkgs> {}; in
pkgs.buildGoModule {
  pname = "toolbox"; version = "0.1.0";
  src = ./.; vendorHash = null;   # keine externen Module
}
# $ nix-build toolbox.nix && ./result/bin/toolbox

Das ist eine vollständige, reproduzierbare Paket-Definition für ein echtes Programm.

Primärquelle zum Lesen nixpkgs Manual – Go (buildGoModule). Die maßgebliche Referenz inkl. vendorHash. Vergleich dann kurz mit einem zweiten Builder deiner Wahl – das Muster wiederholt sich.
Ich bin dein Teacher. Dein Workshop-Beispiel ist Python oder Rust statt Go? Sag mir die Sprache – ich gebe dir die passende Builder-Vorlage mit dem richtigen Dependency-Hash.
← Lektion 9 · Eigene Pakete I Lektion 11 · Paket in die Dev-Shell →
Als Nächstes: Lektion 11 – Paket in die Dev-Shell (callPackage, Overlays)