1 Punkte von GN⁺ 5 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • Nix Flakes bündeln Projektabhängigkeiten, Locking, Ausgabe-Schema und Entwicklungsumgebungen rund um flake.nix und flake.lock, während Guix dieselbe Art von Funktionen durch die Kombination orthogonaler Werkzeuge wie Channels, Manifests, guix describe, guix shell und operating-system bereitstellt
  • Flakes fixieren Abhängigkeiten über projektbezogene inputs und ein automatisch erzeugtes flake.lock, während Guix mit benutzerbezogenem guix describe, einem im Projekt mit Commits festgehaltenen channels.scm und guix time-machine reproduzierbare Umgebungen aufbaut
  • Reinheit wird bei Flakes durch restricted evaluation erzwungen, während sie in Guix durch die Struktur der Scheme-Module, explizite Eingaben und isolierte Build-Container von Grund auf erreicht wird
  • Ausgabestruktur: Flakes bieten standardisierte Attrsets wie packages, devShells und nixosConfigurations, während Guix transparente Scheme-Records und Dateien wie <package>, Manifest, operating-system und Service verwendet, die von den jeweiligen Befehlen direkt konsumiert werden
  • Auswahlkriterium: Wer einen einzelnen Einstiegspunkt und ein standardisiertes Schema bevorzugt, ist mit Flakes gut bedient; wer lieber kleine, unabhängige Werkzeuge kombiniert, fährt mit Guix besser

Zentrale Gegenüberstellung

  • Es gibt keine einzelne Guix-Funktion, die einem Nix Flake entspricht; während Nix Flakes mehrere Probleme als ein großes Feature lösen, setzt Guix auf die Kombination kleinerer, orthogonaler Werkzeuge
  • Guix hat den Nix-Daemon wiederverwendet und teilt sich die C++-Komponenten für Build-Isolation und Store-Management
  • Guix implementiert den Großteil oberhalb des Nix-Daemons — etwa Sprache, Paketdefinitionen und Servicesystem — neu in Guile Scheme
  • Guix und Nix teilen sich das Derivation-Format ATerm und die Abstammung des Daemons, aber die Struktur oberhalb des Daemons ist in Guix auf eigene Weise aufgebaut
  • Guix verfügt über die Capabilities, die Flakes bieten, stellt sie aber in anderer Form bereit

Grundstruktur eines Nix Flake

  • Ein Nix Flake ist ein Source Tree mit einer flake.nix-Datei im Root und liegt meist als Git-Repository vor
  • Das Vorhandensein von flake.nix macht den Source Tree zu einem Flake; die Datei hat typischerweise eine Struktur mit description, inputs und outputs
  • description ist eine menschenlesbare Zeichenkette, die angibt, was der Flake bereitstellt
  • inputs deklarieren Abhängigkeiten wie andere Flakes, Git-Repos oder Tarballs; Nix lädt sie, evaluiert sie und übergibt sie dann an die Funktion outputs
  • outputs ist eine Funktion, die die aufgelösten Inputs und den speziellen Input self entgegennimmt und ein strukturiertes Attrset mit Paketen, Dev Shells, NixOS-Konfigurationen, Overlays usw. zurückgibt
  • Beispielstruktur und Ausführungsziele

    • Das Beispiel-inputs mit nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; bedeutet, dass der Branch nixos-unstable aus dem GitHub-Repository NixOS/nixpkgs geholt wird
    • Der Beispiel-Flake verwendet supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" ]; und nixpkgs.lib.genAttrs, um Outputs für mehrere CPU-Architekturen zu erzeugen
    • Flakes verlangen die Ebene packages.<system>; im Beispiel wird darunter das default-Paket mit pkgs.buildGoModule definiert
    • src = ./.; verwendet das gesamte Git-Repository als Source
    • devShells definiert die Entwicklungs-Shell, auf die sich nix develop bezieht; im Beispiel werden pkgs.mkShell und buildInputs = with pkgs; [ go gopls gotools ]; verwendet
  • flake.lock und reine Auswertung

    • Wenn ein Nix-Befehl für einen Flake ausgeführt wird, erzeugt Nix die JSON-Datei flake.lock, die alle Inputs und transitiven Inputs auf exakte Revisionen festlegt
    • flake.lock ist eine Lock-Datei, die reproduzierbare Builds über Maschinen und Zeit hinweg ermöglicht
    • Flakes erzwingen pure evaluation: $NIX_PATH, builtins.currentSystem und Umgebungsvariablen werden nicht implizit hereingegeben, alles muss explizit sein
    • Die von Flakes bereitgestellten Funktionen lassen sich zusammenfassen als Deklaration von Abhängigkeiten, Pinning von Abhängigkeiten, Erzwingung von Reinheit, Bereitstellung eines standardisierten Ausgabe-Schemas, reproduzierbares Teilen und Definition von Entwicklungsumgebungen

Der entsprechende Ansatz von Guix

  • Guix hatte bereits Lösungen für einen erheblichen Teil der Flakes-Funktionen, bevor Flakes am 1. November 2021 in Nix 2.4 eingeführt wurden
  • Der Guix-Mechanismus für Channels wurde etwa 2018–2019 eingeführt
  • Die Lösung von Guix ist orthogonal; statt eine einzelne monolithische Abstraktion zu übernehmen, können die jeweiligen Werkzeuge unabhängig voneinander verwendet werden
  • Channels und Deklaration von Abhängigkeiten

    • In einem Flake werden Abhängigkeiten direkt in flake.nix deklariert; im Beispiel werden nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; und home-manager.url = "github:nix-community/home-manager"; verwendet
    • inputs.nixpkgs.follows = "nixpkgs"; bei einem Flake-Input sorgt dafür, dass nicht das eigene nixpkgs-Input von home-manager verwendet wird, sondern das nixpkgs des aktuellen Flakes, und vermeidet so die Situation, dass zwei unterschiedliche nixpkgs-Kopien entstehen
    • Channels in Guix sind Git-Repositories, die Guile-Module enthalten; meist enthalten sie Paketdefinitionen, können aber auch Services, Systemkonfigurationen und beliebigen Scheme-Code umfassen
    • Guix-Channels werden in ~/.config/guix/channels.scm deklariert; diese Scheme-Datei gibt eine Liste von Channel-Records zurück
    • guix pull holt und kompiliert alle Channels und macht die entsprechenden Module in allen guix-Kommandos verfügbar
    • Channels können mit der Datei .guix-channel im Repository-Root Abhängigkeiten zu anderen Channels deklarieren
    • Channel-Abhängigkeiten in Guix sind den inputs eines Flakes grob ähnlich; beim Ausführen von guix pull werden auch transitive Channel-Abhängigkeiten mitgeholt
  • Projektbezogene und benutzerbezogene Abhängigkeiten

    • Flakes arbeiten projektbezogen, sodass jedes Repository seine eigene flake.nix und eigene Inputs hat; Channels arbeiten systemweit oder pro Benutzer, sodass channels.scm für alle guix-Aufrufe gilt
    • Flakes unterstützen auf natürliche Weise, dass unterschiedliche Projekte unterschiedliche Abhängigkeitsmengen haben; in Guix verwendet man für denselben Effekt üblicherweise guix time-machine oder separate Profile
    • Flakes verwenden eine URL-ähnliche Syntax wie github:NixOS/nixpkgs, git+https://...; Channels verwenden einfache Git-URLs
    • Die Flake-Syntax ist für schnelle Referenzen ergonomischer, Channels sind einfacher und expliziter
    • Flakes unterstützen mit flake = false; auch Repositories ohne flake.nix als Non-Flake-Inputs
    • In Guix ist ein Channel ein Git-Repository mit Scheme-Dateien, daher ist kein besonderes Opt-in nötig; jedes Repository mit Guile-Modulen kann ein Channel sein

Pinning, Reproduzierbarkeit und Zeitreise

  • flake.lock

    • flake.lock ist ein JSON-Graph; alle Inputs werden auf genaue Commit-Hashes festgelegt, und Nix prüft den narHash, also den Hash des vollständig geholten Source-Trees
    • flake.lock wird ins Repository committed, sodass jeder, der es klont, dieselben Dependency-Versionen erhält
    • original in flake.lock ist das angeforderte Ziel, locked das tatsächlich erhaltene Ziel
    • Das Two-Layer-System von flake.lock ermöglicht selektive Updates, bei denen zum Beispiel nur ein bestimmter Input mit nix flake lock --update-input nixpkgs aktualisiert wird und der Rest unverändert bleibt
  • guix describe und guix time-machine

    • Guix zeichnet beim Ausführen von guix pull die exakten Commits aller Channels auf, und guix describe zeigt diese Informationen an
    • Die Ausgabe von guix describe enthält Generationsnummer, Datum, Kennzeichnung des aktuellen Zustands, Channel-Namen, Repository-URL, Branch und Commit
    • Die aufgezeichneten Channel-Commits in Guix entsprechen einer Lock-Datei, liegen aber nicht als Datei im Projektverzeichnis vor, sondern als Guile-Profil in ~/.config/guix/current
    • Um reproduzierbare Umgebungen zu teilen, kann man in Guix guix time-machine verwenden
    • guix time-machine --commit=8a1ab328 -- shell -m manifest.scm fixiert zunächst Guix selbst auf eine bestimmte Revision und führt dann guix shell mit den Paketdefinitionen dieser Revision aus
    • guix time-machine lädt und kompiliert bei Bedarf die betreffende Revision und erzeugt eine isolierte Umgebung, in der die Paketdefinitionen exakt dem Stand dieses Commits entsprechen
    • In Guix gibt es auch das Muster, ein channels.scm mit festgelegten Commits ins Projekt-Repository einzuchecken
    • guix time-machine -C channels.scm -- shell -m manifest.scm reproduziert die exakte Umgebung mithilfe des im Repository enthaltenen channels.scm
  • Unterschiede zwischen beiden Ansätzen

    • flake.lock ist projektbezogen und automatisch, guix describe ist benutzerbezogen und automatisch
    • Ein channels.scm mit festgelegten Commits bietet in Guix projektbezogenes Pinning, aber auf manuelle Weise
    • Guix arbeitet daran, die Ergonomie für projektbezogenes Pinning zu verbessern, aber der aktuelle Workflow erfordert ein expliziteres Setup
    • flake.lock ist ein maschinenlesbarer JSON-Graph, das Guix-Gegenstück ist eine Scheme-Datei, die Channels mit Commit-Hashes auflistet
    • Beide Ansätze erreichen das Ziel des Dependency-Pinnings, aber der Flake-Lock ist durch den vollständigen Abhängigkeitsgraphen mit original- und locked-Einträgen für alle transitiven Inputs stärker strukturiert
    • guix time-machine ist eine Funktion ohne direktes Flake-Äquivalent; damit kann man nicht nur zu festgelegten Dependency-Versionen wechseln, sondern zum vollständig anderen historischen Zustand der Paketsammlung

Reinheitsmodell

  • Flakes werden in einem eingeschränkten Evaluierungskontext ausgeführt; die Verwendung von builtins.currentSystem, builtins.getEnv und $NIX_PATH ist verboten oder wird ignoriert
  • In Flakes muss alles aus deklarierten Inputs stammen, sodass versehentliche Abhängigkeiten von implizitem Zustand schwer entstehen können
  • Der Trade-off der reinen Evaluierung bei Flakes besteht darin, dass für die Systemerkennung an vielen Stellen explizite system-Parameter nötig sind und Umgebungsvariablen nicht gelesen werden können
  • Wenn in Flakes ein unreinheitsbedingter Escape Hatch benötigt wird, muss explizit --impure übergeben werden
  • Guix benötigt keinen separaten Modus für reine Evaluierung, da die Evaluierung konventionsgemäß bereits rein ist
  • Guile-Module greifen nicht auf Umgebungsvariablen zu, sofern diese nicht explizit übergeben werden
  • In Guix gibt es kein Gegenstück zu $NIX_PATH; Pakete werden nicht über einen Suchpfad, sondern über das Modulsystem aufgelöst
  • In Guix gibt es kein Konzept, das builtins.currentSystem entspricht; Systeme werden explizit über Paketmetadaten und das Flag --system angegeben
  • Auch die Builds in Guix sind rein; Builds laufen in isolierten Containern, in denen nur explizit deklarierte Inputs sichtbar sind
  • In Guix-Builds gibt es keinen Zugriff auf /usr/bin, /etc oder das Netzwerk; Ausnahmen für Netzwerkzugriff sind auf Fixed-Output-Derivations beschränkt
  • Das Build-Sandboxing von Nix und Guix folgt im Wesentlichen demselben Ansatz
  • Guix erreicht Reinheit architektonisch durch die Struktur der Scheme-Module, während Flakes Reinheit erzwingen, indem sie einem ursprünglich unreineren System einen eingeschränkten Evaluierungsmodus aufsetzen

Ausgabe-Schema und Datenmodell

  • Flake-Ausgabe-Schema

    • Flakes definieren ein Standardschema für Outputs; packages.<system>.<name> wird von nix build verwendet, devShells.<system>.<name> von nix develop und apps.<system>.<name> von nix run
    • Das Flake-Ausgabe-Schema umfasst außerdem nixosConfigurations.<name>, overlays.<name>, nixosModules.<name>, formatter.<system>, templates.<name> und checks.<system>.<name>
    • Die Standardisierung des Flake-Ausgabe-Schemas sorgt dafür, dass nix build ., nix run und nix flake show auf konsistente Stellen verweisen, was die Auffindbarkeit erhöht
    • Ein Nachteil des Flake-Ausgabe-Schemas ist seine Starrheit; um beliebige Output-Typen hinzuzufügen, sind Änderungen an Nix selbst nötig, auch wenn es einen kleinen Erweiterungsmechanismus gibt
    • Wegen des <system>-Parameters muss Multi-Plattform-Support explizit behandelt werden; dafür werden Helper-Funktionen oder Bibliotheken wie forAllSystems, flake-utils oder flake-parts verwendet
  • First-Class-Datentypen in Guix

    • In Guix gibt es kein einzelnes Ausgabe-Schema wie bei Flakes, sondern First-Class-Datentypen, die von verschiedenen Befehlen genutzt werden können
    • In Guix werden Pakete als <package>-Records definiert und von guix install sowie guix build verwendet
    • In Guix werden Manifeste als Scheme-Dateien definiert und von guix shell -m sowie guix package verwendet
    • In Guix werden Systemkonfigurationen als operating-system definiert und von guix system reconfigure verwendet
    • In Guix werden Home-Konfigurationen als home-environment definiert und von guix home reconfigure verwendet
    • In Guix werden Services als <service>-Records definiert, die im Feld services von operating-system verwendet werden
    • In Guix sind Channels Git-Repositories, die von guix pull verwendet werden
    • In Guix sind Paketvarianten Scheme-Prozeduren; verwendet werden --with-input und --transform
  • Dateien und Paketdefinitionen

    • Ein Guix-Projekt kann eine Kombination aus einem Channel mit Paketdefinitionen, manifest.scm für die Entwicklung, system.scm für Deployment sowie Deklarationen wie operating-system oder home-environment bereitstellen
    • In Guix erfordern diese Dateien keine spezielle Entry-Point-Datei; es sind einfach Scheme-Dateien, die Scheme-Werte definieren
    • In Guix verarbeitet der jeweilige Befehl die Datei, wenn man sie dem passenden guix-Unterbefehl angibt; separate Zeremonie oder Schema-Validierung ist nicht nötig
    • Ein Beispiel für manifest.scm deklariert eine Entwicklungsumgebung, indem an specifications->manifest eine Liste mit Paketnamen wie "guile", "guile-git" und "guile-json" übergeben wird
    • Ein Beispiel für mylib.scm definiert einen <package>-Record als Guix-Entsprechung zu einer Nix-Derivation; Paketfelder lassen sich programmatisch abfragen
    • Eine Beispiel-Paketdefinition enthält (name "mylib"), (version "0.1.0"), (source (local-file ".")), (build-system gnu-build-system), (inputs (list guile guile-git)), (home-page "https://example.com";) und (license gpl3+)
    • local-file in Guix übernimmt Dateien aus dem aktuellen Verzeichnis zur Build-Zeit und ist ähnlich zu src = ./.; in Nix
    • gnu-build-system in Guix folgt dem Muster ./configure && make && make install; daneben gibt es weitere Build-Systeme wie cmake-build-system und python-build-system
    • Anders als in Nix, wo stdenv implizit gcc und coreutils bereitstellt, hält Guix alle Abhängigkeiten explizit

Entwicklungsumgebungen

  • Im Beispiel für devShells von Flakes wird devShells.x86_64-linux.default = pkgs.mkShell { buildInputs = with pkgs; [ go gopls gotools ]; shellHook = '' echo "Welcome to the devShell!" ''; }; verwendet
  • mkShell erzeugt eine Derivation, die beim Build eine Shell-Umgebung erstellt; buildInputs wird in den PATH innerhalb der Shell aufgenommen, und shellHook führt beim Betreten der Shell beliebigen Bash-Code aus
  • In eine Flake-Dev-Shell gelangt man mit nix develop oder für eine benannte Shell mit nix develop .#my-shell
  • Eine Guix-Entwicklungsumgebung kann in manifest.scm definiert werden, indem an specifications->manifest eine Liste von Package-Specification-Strings übergeben wird
  • Das beispielhafte Guix-Manifest deklariert "go", "gopls", "go-tools"
  • Eine auf einem Guix-Manifest basierende Shell wird mit guix shell -m manifest.scm gestartet
  • Für ad-hoc-Umgebungen kann Guix auch ohne Datei nur Package-Namen auf der Kommandozeile entgegennehmen, etwa guix shell go gopls go-tools
  • guix shell unterstützt --container für vollständige Isolation, --emulate-fhs zum Ausführen von Programmen, die das Standard-Linux-Dateisystemlayout erwarten, und --nesting, um Guix innerhalb eines Guix-Containers auszuführen
  • Guix-Manifeste sind eigenständige Scheme-Dateien, die nicht in eine größere flake.nix-Struktur eingebettet sind
  • guix shell kann auch ohne Datei arbeiten, aber nix develop benötigt ein Flake oder shell.nix aus der Legacy-Schnittstelle
  • Flakes bieten benannte Dev-Shells wie devShells.x86_64-linux.test und devShells.x86_64-linux.default
  • Bei Guix-Manifests werden statt benannter Dev-Shells separate Dateien wie manifest.scm und test-manifest.scm nebeneinander verwendet
  • Sowohl Nix Flakes als auch Guix unterstützen containerisierte Entwicklung

Systemkonfiguration

  • NixOS und Flakes

    • Im Beispiel für nixosConfigurations von Flakes nimmt nixpkgs.lib.nixosSystem eine Liste von NixOS-Modulen entgegen und erzeugt eine vollständige System-Derivation einschließlich Kernel, Services, Konfigurationsdateien und mehr
    • Der Beispielbefehl für eine flakebasierte NixOS-Bereitstellung lautet nixos-rebuild switch --flake .#myhost
    • Das beispielhafte nixosConfigurations.myhost enthält system = "x86_64-linux"; und modules = [ ./configuration.nix home-manager.nixosModules.home-manager ];
    • NixOS-Module verwenden ein Modulsystem mit prioritätsbasiertem Merging über options, config, mkIf, mkDefault und mkForce
    • Das NixOS-Modulsystem löst Prioritäten auf, selbst wenn mehrere Module dieselbe Option setzen, und erleichtert es so, Konflikte zu vermeiden, auch wenn Dutzende Module zur gleichen Konfiguration beitragen
  • Guix operating-system

    • Guixs operating-system ist keine Funktion, sondern ein Scheme-Record, dessen Felder benannte, typisierte Werte sind, die von Guix validiert werden
    • Der Beispielbefehl für eine Guix-Systembereitstellung lautet guix system reconfigure config.scm
    • Das Beispiel für den operating-system-Record enthält (host-name "myhost"), (timezone "Etc/UTC"), eine Bootloader-Konfiguration, Dateisysteme und Services
    • Das Beispiel für die Guix-Bootloader-Konfiguration verwendet grub-efi-bootloader mit dem Ziel "/boot/efi"; Guix unterstützt unter anderem GRUB und U-Boot
    • Guix-Dateisysteme werden als Liste deklariert, und %base-file-systems liefert Standardwerte für /dev, /proc, /sys und weitere
    • Guix-Services bilden einen gerichteten azyklischen Graphen (DAG), und jeder Service kann andere Services erweitern
    • %base-services stellt essenzielle Services wie das Init-System Shepherd, Syslog und Netzwerkdienste bereit
    • Für die Guix-Systemkonfiguration ist kein spezieller Output-Typ erforderlich; es genügt, guix system eine Datei zu übergeben, die einen operating-system-Record zurückgibt
    • Die Service-Kombination in Guix macht es leicht, neue Services zu schreiben, die sich auf beliebige Weise an ein bestehendes System andocken

Auffindbarkeit und Registry

  • Flakes haben mit flake.nix einen standardisierten Einstiegspunkt, der Projektabhängigkeiten, Outputs und ein auffindbares Schema in einer Datei deklariert
  • Guix-Projekte können konventionsbasierte Dateien wie manifest.scm, channels.scm, guix.scm und package.scm verwenden
  • Es gibt Bestrebungen, guix.scm als Projektdatei zu standardisieren, die von guix shell automatisch erkannt wird, aber das ist noch nicht so etabliert wie flake.nix
  • Flakes haben mit flake-registry eine globale Registry, die Kurznamen auf URLs abbildet; Beispiele sind nix run nixpkgs#hello und nix build github:NixOS/nixpkgs#firefox
  • Guix nutzt für ähnliche Bequemlichkeit Paketangaben, etwa guix shell hello und guix install firefox
  • Guix hat kein Pendant zu einer Registry, die beliebige Git-Repositories über Kurznamen referenziert, sondern verwendet URLs direkt
  • Die Nix-Registry war immer wieder eine Quelle von Verwirrung, weil nicht stets klar ist, ob nixpkgs ein Registry-Eintrag, ein lokaler Pfad oder ein anderes Ziel ist
  • nix flake show ist ein Befehl, der alles, was ein Flake anbietet, in einer Baumansicht anzeigt
  • Guix bietet guix search für Pakete und guix system search für Services, aber keinen entsprechenden Befehl, der alles zeigt, was ein bestimmtes Projekt oder Repository bereitstellt; dafür muss man die Scheme-Dateien direkt prüfen
  • Flakes sind bei der Auffindbarkeit stark, weil nix flake show eine konsistente Sicht auf das bietet, was ein Projekt bereitstellt
  • Guix-Projekte sind eher ad hoc; man muss wissen, welche Dateien man ansehen muss, und es gibt keine standardisierte Datei mit einem einzigen Einstiegspunkt
  • Guix ist stark in der Flexibilität, weil alles Scheme ist und sich Dinge ohne Schema beliebig definieren und kombinieren lassen

Paketmodell und Umschreiben von Graphen

  • In Nix sind Pakete Funktionen, die über einen Aufruf von stdenv.mkDerivation { ... } eine Derivation zurückgeben; das Ergebnis ist ein undurchsichtiges Attributset.
  • In Guix sind Pakete <package>-Records, also transparente Datenstrukturen mit benannten Feldern, die sich mit Standard-Scheme-Prozeduren untersuchen, transformieren und kombinieren lassen.
  • Da Guix-Paketdefinitionen keine opaque functions, sondern transparente Records sind, können inspect und transform ohne spezielles Tooling programmatisch durchgeführt werden.
  • In Guix sind Pakete Daten, daher lassen sich graph rewrites leicht durchführen.
  • In Guix kann man mit package-input-rewriting ausdrücken, dass der gesamte Abhängigkeitsgraph durchlaufen und perl durch perl-minimal ersetzt wird.
  • Das Schlüsselwort inherit in Guix definiert ein Paket neu, indem es alle Felder von coreutils übernimmt und nur die angegebenen Felder überschreibt.
  • In Nix gibt es mit ähnlicher Zielsetzung Overlays, doch wegen der undurchsichtigen Funktionsschnittstelle sind Untersuchung und Transformation schwieriger und weniger benutzerfreundlich.

Sicherheitsupdates, Bootstrapping, Authentifizierung

  • Grafting in Guix ermöglicht es, Sicherheitsupdates in einem Abhängigkeitsbaum anzuwenden, ohne alle abhängigen Pakete neu zu bauen.
  • Wenn eine Low-Level-Bibliothek wie glibc eine Schwachstelle hat, kann Guix Store-Pfade umschreiben und sie durch eine gepatchte Version ersetzen.
  • Nix baut bei Sicherheitsupdates alles neu; bei großen Abhängigkeitsbäumen kann das mehrere Stunden Unterschied bei der Build-Zeit ausmachen.
  • Guix legt starken Fokus auf quellbasiertes Bootstrapping, sodass sich das gesamte System aus einer kleinen Vertrauensbasis heraus bauen lässt.
  • Die Bootstrapping-Kette von Guix beginnt bei einem etwa 500 Byte großen hex assembler und führt über den in Scheme geschriebenen mes-C-Compiler und tcc bis zur vollständigen GNU-Toolchain.
  • Das Projekt bootstrappable builds behandelt die Details des vollständigen Source-Bootstrappings.
  • Nix ist stärker als Guix auf binäre Seeds angewiesen.
  • Wenn sich die Bootstrapping-Kette nicht auditieren lässt, kann nicht vollständig verifiziert werden, ob das System tatsächlich aus dem vorgesehenen Quellcode gebaut wurde; vollständiges Source-Bootstrapping ist daher wichtig für Vertrauen und Verifizierbarkeit.
  • Guix-Channels unterstützen standardmäßig kryptografische Authentifizierung.
  • Ein Guix-Channel gibt eine „introduction“ an, die aus einem bestimmten Commit und dessen Ed25519-Signatur besteht; Guix verifiziert die gesamte Signaturkette von dieser Introduction bis zum aktuellen Commit.
  • Flakes verwenden HTTPS und die GitHub-Infrastruktur als Vertrauensmodell; das ist ein anderes Sicherheitsmodell als die Ed25519-Channel-Authentifizierung von Guix.

Zentrale Entsprechungen in der Übersichtstabelle

  • Bei der Deklaration von Abhängigkeiten verwenden Flakes inputs in flake.nix, Guix verwendet channels.scm und .guix-channel.
  • Für das Fixieren von Abhängigkeiten nutzen Flakes automatisch und projektspezifisch flake.lock, während Guix benutzerspezifisch automatisch guix describe und projektspezifisch manuell commit-fixierte channels.scm verwendet.
  • Reine Auswertung wird im Flake-Modus erzwungen und ist in Guix von Haus aus Teil des Designs.
  • Beim Ausgabeschema verwenden Flakes ein strukturiertes Attrset in outputs, Guix dagegen ad-hoc Scheme-Records.
  • Für Entwicklungsumgebungen verwenden Flakes devShells und nix develop, Guix manifest.scm und guix shell.
  • Für die Systemkonfiguration verwenden Flakes nixosConfigurations und das Modulsystem, Guix operating-system und einen Service-DAG.
  • Reproduzierbarkeit per Ein-Kommando-Aufruf hat bei Flakes die Form nix build github:foo/bar, bei Guix die Form guix time-machine -C channels.scm -- build.
  • Projektspezifisches Fixieren wird bei Flakes automatisch über flake.lock erledigt, bei Guix manuell über channels.scm mit Commit-Angabe.
  • Für Auffindbarkeit bieten Flakes nix flake show, während Guix auf die Untersuchung von Scheme-Modulen setzt.
  • Beim Paketmodell sind Flakes/Nix undurchsichtige Funktionen, Guix verwendet transparente Records.
  • Als init system verwendet Nix systemd, Guix GNU Shepherd.
  • Bei Sicherheitsupdates setzt Nix auf kompletten Rebuild, Guix auf schnelles Grafting.
  • Beim Bootstrap-Vertrauen basiert Nix auf binären Seeds, Guix auf vollständigem Source-Bootstrapping.
  • Für authentifizierte Updates setzt Flakes auf Vertrauen in HTTPS/GitHub, Guix auf Ed25519-Channel-Authentifizierung.
  • FHS-Unterstützung bietet Nix mit buildFHSUserEnv, Guix mit --emulate-fhs.
  • Jenseits von Linux unterstützt Nix macOS über nix-darwin, Guix ist auf GNU Hurd ausgerichtet.
  • Hinsichtlich ausschließlicher Freie-Software-Ausrichtung ist Nix nicht ausschließlich darauf beschränkt und konfigurierbar, während Guix den FSDG entspricht.

Fazit

  • Flakes und Guix lösen dieselben Problemklassen rund um Reproduzierbarkeit, Abhängigkeitsmanagement und Systemdeklaration, aber mit unterschiedlichen Architekturphilosophien.
  • Flakes kommen einer einzelnen Funktion nahe: eine Datei, ein Schema, eine Lock-Datei, ein Satz von Konventionen.
  • Guix ist eine Kombination orthogonaler Werkzeuge wie Channels für Distribution, Manifeste für Umgebungen, operating-system für Konfiguration, guix time-machine für Reproduzierbarkeit und Scheme-Records für andere Strukturen.
  • Wenn man eine standardisierte Vorgehensweise, eine einzige Einstiegspunkt-Datei, ein einziges Ausgabeschema und ein einziges Lock-Format bevorzugt, passen Flakes ganz natürlich.
  • Wenn man bevorzugt, kleine unabhängige Werkzeuge zu kombinieren, sodass jedes Werkzeug im Sinne der Unix-Philosophie eine Sache gut macht, passt Guix gut.
  • Beide Ökosysteme haben sich rund um die Idee entwickelt, dass Paketverwaltung funktional, deklarativ und reproduzierbar sein sollte, und treiben dieselbe Idee mit unterschiedlichen Implementierungen voran.

1 Kommentare

 
GN⁺ 5 시간 전
Lobste.rs-Meinungen
  • Diese Seite ist auf Mobilgeräten viel zu frustrierend zu lesen: Die Schrift ist etwas zu klein, und beim Scrollen stört sie ständig
    Nach dem ersten Vergleich konnte ich nicht mehr weiterlesen, weil ich ständig zum Inhaltsverzeichnis zurückgesprungen bin

    • Sie ist praktisch unlesbar. Es bewegt sich wie ein Jo-Jo. Das war einer der Artikel, die ich in letzter Zeit wirklich lesen wollte, deshalb bin ich von dieser extrem frustrierenden Leseerfahrung enttäuscht
    • Dasselbe passiert auch auf dem Desktop. Das ist absurd und wirkt so, als hätte man die Barrierefreiheit absichtlich kaputtgemacht
  • Auch nach dem Lesen des Artikels ist mir noch nicht klar, wie man die Abhängigkeiten eines Projekts angeben und pinnen soll. Es sieht so aus, als müsste man zum Veröffentlichen und Teilen die Commit-Hashes jeder transitiven Abhängigkeit manuell in channels.scm eintragen
    time-machine scheint nur auf die Guix-Paketmenge zu wirken, nicht auf Abhängigkeiten außerhalb des Baums
    Wie bei nix run github:nixos/nixpkgs/<commit hash>#<package> kann man auch Code aus einem früheren Stand von nixpkgs ziemlich einfach ausführen
    Ein ungewöhnlicher Punkt bei Guix ist, dass die Version der Paketsammlung und die Version des Paketmanagers nicht getrennt werden. Um alte Pakete auszuführen, startet man damit auch eine alte Guix-Release mit, und ich verstehe nicht recht, warum man das wollen sollte
    Im Artikel wird gesagt, dass man bei Flakes Commits manuell suchen und angeben müsse, und direkt danach wird als Beispiel ein Guix-Befehl gezeigt, bei dem ebenfalls Commits angegeben werden müssen. In Nix Flakes kann man die nixpkgs-Version auch mit --override-input überschreiben, aber das ist unsauber, und genau das ist einer der Punkte, die unflake verbessern will

    • Ich habe zwar weniger praktische Erfahrung mit Guix als der Autor, habe aber immerhin etwas in die Dokumentation geschaut, also versuche ich ein paar Antworten
      Normalerweise entwickelt man in einer dedizierten guix shell-Umgebung und wenn es ans Teilen geht, schreibt man mit guix describe -f channels > channels.scm alle Commit-Hashes in channels.scm
      Wenn man die Doku zu declaring channel dependencies liest, kann man Commit-Hashes für Abhängigkeiten angeben, aber es scheint keine Option zu geben, zu prüfen, ob auch die Abhängigkeiten dieser Abhängigkeiten auf bestimmte Commits festgelegt sind
      Die --commit=-Schreibweise von time-machine bezieht sich auf den Guix-Channel, aber mit -C kann man zusätzlich Channels aus einer Datei laden
      Das hat den Vorteil, dass man trotz inkompatibler Änderungen am Paketmanager und an den Paketdefinitionen Historie und Reproduzierbarkeit behält
    • Dafür könnte man einen inversen Index für nixpkgs erstellen: also dass die Commits X bis Y von nixpkgs Version A eines bestimmten Pakets enthalten
      Allerdings müsste man dafür für jeden Commit einen nixpkgs-Checkout machen, wodurch die anfänglichen Erstellungskosten sehr hoch wären. Wenn der Index einmal existiert, dürften die Pflegekosten gering sein
  • Ich habe coopi auf die Probleme der Seite und auf diesen Thread hingewiesen, hoffentlich wird es bald behoben
    Als jemand, der inzwischen stark zu Guix tendiert, würde ich mir wie von coopi gesagt auch für Guix eine standardisierte Datei bzw. ein standardisiertes Verzeichnis wünschen, die alles enthalten, also so etwas wie eine einzelne flake.nix oder ein nix-Verzeichnis. Allerdings könnte das unmöglich sein, weil man zum Importieren von Scheme-Modulen die richtigen Pfade angeben muss
    In diesem Lobsters-Post steht, worüber der Autor spricht, daher scheinen die Tags nix und lisp auszureichen

    • Ich finde das Argument, linux wegzulassen, nicht überzeugend. Das ist schließlich der einzige Kernel, den beide gemeinsam haben :P Allerdings passt unix, wie gesagt, wahrscheinlich wirklich nicht gut
    • Etwas wie ein strukturierter Channel-Datentyp, der wie bei Flakes hilft, automatisch abzuleiten, was ein Channel bereitstellt, wäre auch schön
      Zum Beispiel so:
      (channel  
        (operating-systems  
          (list my-vm))  
        (services  
          (list my-system-service)))  
      
      Und ein Befehl guix channel, der beim Erstellen und Verwalten neuer Channels hilft, wäre ebenfalls nützlich
  • Ich frage mich, ob es in Guix auch eine Funktion gibt, mit der man wie bei .inputs.nixpkgs.follows in Nix Flakes Pins transitiver Abhängigkeiten überschreiben kann
    Außerdem erinnert mich ein großer Teil der Guix-Beschreibung des Autors an Nix vor Flakes: keine standardisierten Einstiegspunkte, eine Struktur mit Channels usw. Allerdings wirkt es so, als seien dieselben Muster in Guix weniger schmerzhaft, weil es dort ein Typsystem und eine echte Sprache gibt. Es fühlt sich wie eine Alternativgeschichte dazu an, wie Nix hätte aussehen können, wenn es besser oder in einer anderen Sprache gewesen wäre

    • Wofür verwendet man diese Funktion?
  • Wegen der in anderen Kommentaren angesprochenen Usability-Probleme zögere ich, den Artikel zu empfehlen. Ich habe es nicht bemerkt, weil ich NoScript benutze und JavaScript standardmäßig deaktiviert habe
    Trotzdem kam dieser Artikel genau zum richtigen Zeitpunkt. Bei uns in der Firma geht es stark in Richtung Nix, und wir schlagen uns ein wenig mit Flakes herum, aber die Erklärung in diesem Artikel war viel klarer als in früheren Texten, die ich gelesen habe

    • Coopi sagte, man habe versucht, dem Prinzip der progressiven Verbesserung zu folgen, damit der Artikel auch ohne JavaScript oder CSS lesbar bleibt; bei JavaScript habe man es vermasselt, aber immerhin habe die Philosophie grundsätzlich funktioniert. Inzwischen sei auch JavaScript repariert worden
  • Antwort von Coopi: Er habe heute Morgen Änderungen vorgenommen, sie wegen der Arbeit aber nicht testen können, und dabei sei ihm aufgefallen, dass es ein Problem mit JavaScript gab

  • Diese Seite ist auf iOS-Mobilgeräten nicht benutzbar. Es sieht so aus, als würde die Seite unten laden und dann sofort nach oben scrollen, und sobald ich mehr als eine Bildschirmhöhe nach unten scrolle, wird irgendetwas ausgelöst, das mich wieder nach oben wirft
    Der Lesemodus funktioniert, aber dabei gehen die Hervorhebungen und das eigentlich ziemlich gute Detail-Styling verloren

  • Es ist zwar richtig zu sagen, dass man das, was Flakes leisten, in Guix auch mit mehreren Werkzeugen erreichen kann, aber man sollte erwähnen, dass Nix schon früher und auch heute noch kleine, orthogonale Werkzeuge hatte, mit denen sich dieselben Probleme lösen lassen
    Was Flakes bieten, ist ein standardisierter Projekteinstiegspunkt und das Ökosystem, das dadurch möglich wird, etwa eine Registry. Im Artikel wird auch gesagt, dass Guix diesen Teil nicht hat
    Guix-Nutzer können zu dem Schluss kommen, dass ein standardisierter Einstiegspunkt nicht nötig ist, und viele Nix-Nutzer sind historisch ebenfalls zu diesem Schluss gekommen
    Aber zu sagen, man könne Flakes mit einer Sammlung orthogonaler Werkzeuge nachbilden, klingt ein bisschen so, als würde man behaupten, FreeBSD brauche keine OCI-Unterstützung, weil man mit Jails alles Nötige machen könne. Das verpasst den Punkt, dass Standardisierung ein Ökosystem ermöglicht
    Ich interessiere mich sehr für Guix und habe auch ein wenig dazu beigetragen, aber ich würde gern vergleichen, warum das Bauen mit guix time-machine zusammen mit channels.scm so viel länger dauert als das Ändern von Flake-Pins und die Nix-Auswertung. Wenn es etwa dreimal so langsam wäre, also zum Beispiel 5–10 Sekunden statt 15–30 Sekunden, könnte ich damit leben, aber bei meinen Versuchen lag es weit darüber