Niemand schreibt installPhase für Go von Hand. buildGoModule macht es richtig.
buildGoModule. Genau dieses Muster brauchst du im Workshop für reale Projekte.
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.
buildGoModuleAngenommen, 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.
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.
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;.
# 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.
nix run ausführbar.
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.
src-Hash (Lektion 9) sichert deinen Quellcode; vendorHash sichert die
Dependencies. Bei src = ./.; entfällt der src-Hash – der vendorHash
bleibt aber nötig.
buildGoModule, für ältere/GOPATH-Projekte buildGoPackage (selten).
Nicht spicken – Abrufen aus dem Gedächtnis ist genau die Übung, die hängen bleibt.
Wozu dient der vendorHash bei buildGoModule?
Da der Build kein Netz hat, lädt Nix die Module separat und prüft sie gegen den
vendorHash – so bleiben auch Dependencies reproduzierbar.
Wie findest du einen unbekannten vendorHash heraus?
Derselbe Trick wie beim src-Hash: fakeHash setzen, einmal bauen, Nix nennt den echten
Hash. Manuelles Rechnen wäre fehleranfällig.
Was haben buildGoModule und buildNpmPackage gemeinsam?
Alle Sprach-Builder sind Spezialisierungen von mkDerivation – mit denselben Phasen,
nur vorausgefüllt. Netz brauchen sie dank Dependency-Hash gerade nicht.
Ziel: Ein minimales Go-CLI mit buildGoModule paketieren.
go mod init toolbox + ein main.go, das etwas ausgibt).toolbox.nix mit buildGoModule, src = ./.; und vendorHash = pkgs.lib.fakeHash;.vendorHash aus dem Fehler und trag ihn ein (oder null, wenn keine Deps)../result/bin/toolbox aus.Tipp: Ohne externe Dependencies ist vendorHash = null; der schnellste Weg.
# 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.
buildGoModule).
Die maßgebliche Referenz inkl. vendorHash. Vergleich dann kurz mit einem zweiten Builder
deiner Wahl – das Muster wiederholt sich.
callPackage, Overlays)