Nächste: , Vorige: , Nach oben: Programmierschnittstelle   [Inhalt][Index]


8.12 G-Ausdrücke

Es gibt also „Ableitungen“, die eine Abfolge von Erstellungsaktionen repräsentieren, die durchgeführt werden müssen, um ein Objekt im Store zu erzeugen (siehe Ableitungen). Diese Erstellungsaktionen werden durchgeführt, nachdem der Daemon gebeten wurde, die Ableitungen tatsächlich zu erstellen; dann führt der Daemon sie in einer isolierten Umgebung (einem sogenannten Container) aus (siehe Aufruf von guix-daemon).

Wenig überraschend ist, dass wir diese Erstellungsaktionen gerne in Scheme schreiben würden. Wenn wir das tun, bekommen wir zwei verschiedene Schichten von Scheme-Code23: den „wirtsseitigen Code“ („host code“) – also Code, der Pakete definiert, mit dem Daemon kommuniziert etc. – und den „erstellungsseitigen Code“ („build code“) – also Code, der die Erstellungsaktionen auch wirklich umsetzt, indem Dateien erstellt werden, make aufgerufen wird und so weiter (siehe Erstellungsphasen).

Um eine Ableitung und ihre Erstellungsaktionen zu beschreiben, muss man normalerweise erstellungsseitigen Code im wirtsseitigen Code einbetten. Das bedeutet, man behandelt den erstellungsseitigen Code als Daten, was wegen der Homoikonizität von Scheme – dass Code genauso als Daten repräsentiert werden kann – sehr praktisch ist. Doch brauchen wir hier mehr als nur den normalen Quasimaskierungsmechanismus mit quasiquote in Scheme, wenn wir Erstellungsausdrücke konstruieren möchten.

Das Modul (guix gexp) implementiert G-Ausdrücke, eine Form von S-Ausdrücken, die zu Erstellungsausdrücken angepasst wurden. G-Ausdrücke (englisch „G-expressions“, kurz Gexps) setzen sich grundlegend aus drei syntaktischen Formen zusammen: gexp, ungexp und ungexp-splicing (alternativ einfach: #~, #$ und #$@), die jeweils mit quasiquote, unquote und unquote-splicing vergleichbar sind (siehe quasiquote in Referenzhandbuch zu GNU Guile). Es gibt aber auch erhebliche Unterschiede:

Dieser Mechanismus ist nicht auf Pakete und Ableitung beschränkt: Es können Compiler definiert werden, die weitere abstrakte, hochsprachliche Objekte auf Ableitungen oder Dateien im Store „herunterbrechen“, womit diese Objekte dann auch in G-Ausdrücken eingefügt werden können. Zum Beispiel sind „dateiartige Objekte“ ein nützlicher Typ solcher abstrakter Objekte. Mit ihnen können Dateien leicht in den Store eingefügt und von Ableitungen und anderem referenziert werden (siehe unten local-file und plain-file).

Zur Veranschaulichung dieser Idee soll uns dieses Beispiel eines G-Ausdrucks dienen:

(define build-exp
  #~(begin
      (mkdir #$output)
      (chdir #$output)
      (symlink (string-append #$coreutils "/bin/ls")
               "list-files")))

Indem wir diesen G-Ausdruck an gexp->derivation übergeben, bekommen wir eine Ableitung, die ein Verzeichnis mit genau einer symbolischen Verknüpfung auf /gnu/store/…-coreutils-8.22/bin/ls erstellt:

(gexp->derivation "das-ding" build-exp)

Wie man es erwarten würde, wird die Zeichenkette "/gnu/store/…-coreutils-8.22" anstelle der Referenzen auf das Paket coreutils im eigentlichen Erstellungscode eingefügt und coreutils automatisch zu einer Eingabe der Ableitung gemacht. Genauso wird auch #$output (was äquivalent zur Schreibweise (ungexp output) ist) ersetzt durch eine Zeichenkette mit dem Namen der Ausgabe der Ableitung.

Im Kontext der Cross-Kompilierung bietet es sich an, zwischen Referenzen auf die native Erstellung eines Pakets – also der, die auf dem Wirtssystem ausgeführt werden kann – und Referenzen auf Cross-Erstellungen eines Pakets zu unterscheiden. Hierfür spielt #+ dieselbe Rolle wie #$, steht aber für eine Referenz auf eine native Paketerstellung.

(gexp->derivation "vi"
   #~(begin
       (mkdir #$output)
       (mkdir (string-append #$output "/bin"))
       (system* (string-append #+coreutils "/bin/ln")
                "-s"
                (string-append #$emacs "/bin/emacs")
                (string-append #$output "/bin/vi")))
   #:target "aarch64-linux-gnu")

Im obigen Beispiel wird die native Erstellung der coreutils benutzt, damit ln tatsächlich auf dem Wirtssystem ausgeführt werden kann, aber danach die cross-kompilierte Erstellung von emacs referenziert.

Eine weitere Funktionalität von G-Ausdrücken stellen importierte Module dar. Manchmal will man bestimmte Guile-Module von der „wirtsseitigen Umgebung“ im G-Ausdruck benutzen können, deswegen sollten diese Module in die „erstellungsseitige Umgebung“ importiert werden. Die with-imported-modules-Form macht das möglich:

(let ((build (with-imported-modules '((guix build utils))
               #~(begin
                   (use-modules (guix build utils))
                   (mkdir-p (string-append #$output "/bin"))))))
  (gexp->derivation "leeres-Verzeichnis"
                    #~(begin
                        #$build
                        (display "Erfolg!\n")
                        #t)))

In diesem Beispiel wird das Modul (guix build utils) automatisch in die isolierte Erstellungsumgebung unseres G-Ausdrucks geholt, so dass (use-modules (guix build utils)) wie erwartet funktioniert.

Normalerweise möchten Sie, dass der Abschluss eines Moduls importiert wird – also das Modul und alle Module, von denen es abhängt – statt nur das Modul selbst. Ansonsten scheitern Versuche, das Modul zu benutzen, weil seine Modulabhängigkeiten fehlen. Die Prozedur source-module-closure berechnet den Abschluss eines Moduls, indem es den Kopf seiner Quelldatei analysiert, deswegen schafft die Prozedur hier Abhilfe:

(use-modules (guix modules))   ;„source-module-closure“ verfügbar machen

(with-imported-modules (source-module-closure
                         '((guix build utils)
                           (gnu build image)))
  (gexp->derivation "etwas-mit-vm"
                    #~(begin
                        (use-modules (guix build utils)
                                     (gnu build image))
                        )))

Auf die gleiche Art können Sie auch vorgehen, wenn Sie nicht bloß reine Scheme-Module importieren möchten, sondern auch „Erweiterungen“ wie Guile-Anbindungen von C-Bibliotheken oder andere „vollumfängliche“ Pakete. Sagen wir, Sie bräuchten das Paket guile-json auf der Erstellungsseite, dann könnten Sie es hiermit bekommen:

(use-modules (gnu packages guile))  ;für „guile-json“

(with-extensions (list guile-json)
  (gexp->derivation "etwas-mit-json"
                    #~(begin
                        (use-modules (json))
                        )))

Die syntaktische Form, in der G-Ausdrücke konstruiert werden, ist im Folgenden zusammengefasst.

Makro: #~Ausdruck
Makro: (gexp Ausdruck)

Liefert einen G-Ausdruck, der den Ausdruck enthält. Der Ausdruck kann eine oder mehrere der folgenden Formen enthalten:

#$Objekt
(ungexp Objekt)

Eine Referenz auf das Objekt einführen. Das Objekt kann einen der unterstützten Typen haben, zum Beispiel ein Paket oder eine Ableitung, so dass die ungexp-Form durch deren Ausgabedateiname ersetzt wird – z.B. "/gnu/store/…-coreutils-8.22.

Wenn das Objekt eine Liste ist, wird diese durchlaufen und alle unterstützten Objekte darin auf diese Weise ersetzt.

Wenn das Objekt ein anderer G-Ausdruck ist, wird sein Inhalt eingefügt und seine Abhängigkeiten zu denen des äußeren G-Ausdrucks hinzugefügt.

Wenn das Objekt eine andere Art von Objekt ist, wird es so wie es ist eingefügt.

#$Objekt:Ausgabe
(ungexp Objekt Ausgabe)

Dies verhält sich wie die Form oben, bezieht sich aber ausdrücklich auf die angegebene Ausgabe des Objekts – dies ist nützlich, wenn das Objekt mehrere Ausgaben generiert (siehe Pakete mit mehreren Ausgaben.).

Manchmal wird in einem G-Ausdruck grundsätzlich auf die Ausgabe "out" von etwas verwiesen, aber man möchte ihn eigentlich mit einem Verweis auf eine andere Ausgabe einfügen. Für solche Fälle gibt es die Prozedur gexp-input. Siehe gexp-input.

#+Objekt
#+Objekt:Ausgabe
(ungexp-native Objekt)
(ungexp-native Objekt Ausgabe)

Das Gleiche wie ungexp, jedoch wird im Kontext einer Cross-Kompilierung eine Referenz auf die native Erstellung des Objekts eingefügt.

#$output[:Ausgabe]
(ungexp output [Ausgabe])

Fügt eine Referenz auf die angegebene Ausgabe dieser Ableitung ein, oder auf die Hauptausgabe, wenn keine Ausgabe angegeben wurde.

Dies ist nur bei G-Ausdrücken sinnvoll, die an gexp->derivation übergeben werden.

#$@Liste
(ungexp-splicing Liste)

Das Gleiche wie oben, jedoch wird nur der Inhalt der Liste in die äußere Liste eingespleißt.

#+@Liste
(ungexp-native-splicing Liste)

Das Gleiche, aber referenziert werden native Erstellungen der Objekte in der Liste.

G-Ausdrücke, die mit gexp oder #~ erzeugt wurden, sind zur Laufzeit Objekte vom Typ gexp? (siehe unten).

Makro: with-imported-modules Module Rumpf…

Markiert die in Rumpf… definierten G-Ausdrücke, dass sie in ihrer Ausführungsumgebung die angegebenen Module brauchen.

Jedes Objekt unter den Modulen kann der Name eines Moduls wie (guix build utils) sein, oder es kann nacheinander ein Modulname, ein Pfeil und ein dateiartiges Objekt sein:

`((guix build utils)
  (guix gcrypt)
  ((guix config) => ,(scheme-file "config.scm"
                                  #~(define-module ))))

Im Beispiel oben werden die ersten beiden Module vom Suchpfad genommen und das letzte aus dem angegebenen dateiartigen Objekt erzeugt.

Diese Form hat einen lexikalischen Sichtbarkeitsbereich: Sie wirkt sich auf die direkt in Rumpf… definierten G-Ausdrücke aus, aber nicht auf jene, die, sagen wir, in aus Rumpf… heraus aufgerufenen Prozeduren definiert wurden.

Makro: with-extensions Erweiterungen Rumpf…

Markiert die in Rumpf… definierten G-Ausdrücke, dass sie Erweiterungen in ihrer Erstellungs- und Ausführungsumgebung benötigen. Erweiterungen sind typischerweise eine Liste von Paketobjekten wie zum Beispiel die im Modul (gnu packages guile) definierten.

Konkret werden die unter den Erweiterungen aufgeführten Pakete zum Ladepfad hinzugefügt, während die in Rumpf… aufgeführten importierten Module kompiliert werden und sie werden auch zum Ladepfad des von Rumpf… gelieferten G-Ausdrucks hinzugefügt.

Prozedur: gexp? Objekt

Liefert #t, wenn das Objekt ein G-Ausdruck ist.

G-Ausdrücke sind dazu gedacht, auf die Platte geschrieben zu werden, entweder als Code, der eine Ableitung erstellt, oder als einfache Dateien im Store. Die monadischen Prozeduren unten ermöglichen Ihnen das (siehe Die Store-Monade, wenn Sie mehr Informationen über Monaden suchen).

Monadische Prozedur: gexp->derivation Name Ausdruck [#:system (%current-system)] [#:target #f] [#:graft? #t]  [#:hash #f]

[#:hash-algo #f]  [#:recursive? #f] [#:env-vars ’()] [#:modules ’()]  [#:module-path %load-path]  [#:effective-version "2.2"]  [#:references-graphs #f] [#:allowed-references #f]  [#:disallowed-references #f]  [#:leaked-env-vars #f]  [#:script-name (string-append Name "-builder")]  [#:deprecation-warnings #f]  [#:local-build? #f] [#:substitutable? #t]  [#:properties ’()] [#:guile-for-build #f] Liefert eine Ableitung unter dem Namen, die jeden Ausdruck (ein G-Ausdruck) mit guile-for-build (eine Ableitung) für das System erstellt; der Ausdruck wird dabei in einer Datei namens script-name gespeichert. Wenn „target“ wahr ist, wird es beim Cross-Kompilieren als Zieltripel für mit Ausdruck bezeichnete Pakete benutzt.

modules gilt als veraltet; stattdessen sollte with-imported-modules benutzt werden. Die Bedeutung ist, dass die Module im Ausführungskontext des Ausdrucks verfügbar gemacht werden; modules ist dabei eine Liste von Namen von Guile-Modulen, die im Modulpfad module-path gesucht werden, um sie in den Store zu kopieren, zu kompilieren und im Ladepfad während der Ausführung des Ausdrucks verfügbar zu machen – z.B. ((guix build utils) (guix build gnu-build-system)).

effective-version bestimmt, unter welcher Zeichenkette die Erweiterungen des Ausdrucks zum Suchpfad hinzugefügt werden (siehe with-extensions) – z.B. "2.2".

graft? bestimmt, ob vom Ausdruck benannte Pakete veredelt werden sollen, falls Veredelungen zur Verfügung stehen.

Ist references-graphs wahr, muss es eine Liste von Tupeln in einer der folgenden Formen sein:

(Dateiname Objekt)
(Dateiname Objekt Ausgabe)
(Dateiname Gexp-Input)
(Dateiname Store-Objekt)

Bei jedem Element von references-graphs wird das rechts Stehende automatisch zu einer Eingabe des Erstellungsprozesses vom Ausdruck gemacht. In der Erstellungsumgebung enthält das, was mit Dateiname bezeichnet wird, den Referenzgraphen des entsprechenden Objekts in einem einfachen Textformat.

allowed-references muss entweder #f oder eine Liste von Ausgabenamen und Paketen sein. Eine solche Liste benennt Store-Objekte, die das Ergebnis referenzieren darf. Jede Referenz auf ein nicht dort aufgeführtes Store-Objekt löst einen Erstellungsfehler aus. Genauso funktioniert disallowed-references, was eine Liste von Objekten sein kann, die von den Ausgaben nicht referenziert werden dürfen.

deprecation-warnings bestimmt, ob beim Kompilieren von Modulen Warnungen angezeigt werden sollen, wenn auf als veraltet markierten Code zugegriffen wird. deprecation-warnings kann #f, #t oder 'detailed (detailliert) sein.

Die anderen Argumente verhalten sich wie bei derivation (siehe Ableitungen).

Die im Folgenden erklärten Prozeduren local-file, plain-file, computed-file, program-file und scheme-file liefern dateiartige Objekte. Das bedeutet, dass diese Objekte, wenn sie in einem G-Ausdruck demaskiert werden, zu einer Datei im Store führen. Betrachten Sie zum Beispiel diesen G-Ausdruck:

#~(system* #$(file-append glibc "/sbin/nscd") "-f"
           #$(local-file "/tmp/my-nscd.conf"))

Der Effekt hiervon ist, dass /tmp/my-nscd.conf „interniert“ wird, indem es in den Store kopiert wird. Sobald er umgeschrieben wurde, zum Beispiel über gexp->derivation, referenziert der G-Ausdruck diese Kopie im /gnu/store. Die Datei in /tmp zu bearbeiten oder zu löschen, hat dann keinen Effekt mehr darauf, was der G-Ausdruck tut. plain-file kann in ähnlicher Weise benutzt werden, es unterscheidet sich aber darin, dass dort der Prozedur der Inhalt der Datei als eine Zeichenkette übergeben wird.

Prozedur: local-file Datei [Name] [#:recursive? #f] [#:select? (const #t)]

Liefert ein Objekt, dass die lokale Datei Datei repräsentiert und sie zum Store hinzufügen lässt; dieses Objekt kann in einem G-Ausdruck benutzt werden. Wurde für die Datei ein relativer Dateiname als literaler Ausdruck angegeben, wird sie relativ zur Quelldatei gesucht, in der diese Form steht. Wurde die Datei nicht als literale Zeichenkette angegeben, wird sie zur Laufzeit relativ zum aktuellen Arbeitsverzeichnis gesucht. Die Datei wird unter dem angegebenen Namen im Store abgelegt – als Vorgabe wird dabei der Basisname der Datei genommen.

Ist recursive? wahr, werden in der Datei enthaltene Dateien rekursiv hinzugefügt; ist die Datei eine flache Datei und recursive? ist wahr, wird ihr Inhalt in den Store eingelagert und ihre Berechtigungs-Bits übernommen.

Steht recursive? auf wahr, wird (select? Datei Stat) für jeden Verzeichniseintrag aufgerufen, wobei Datei der absolute Dateiname und Stat das Ergebnis von lstat ist, außer auf den Einträgen, wo select? keinen wahren Wert liefert.

Dies ist das deklarative Gegenstück zur monadischen Prozedur interned-file (siehe interned-file).

Prozedur: plain-file Name Inhalt

Liefert ein Objekt, das eine Textdatei mit dem angegebenen Namen repräsentiert, die den angegebenen Inhalt hat (eine Zeichenkette oder ein Bytevektor), welche zum Store hinzugefügt werden soll.

Dies ist das deklarative Gegenstück zu text-file.

Prozedur: computed-file Name G-Ausdruck [#:local-build? #t] [#:options '()]

Liefert ein Objekt, das das Store-Objekt mit dem Namen repräsentiert, eine Datei oder ein Verzeichnis, das vom G-Ausdruck berechnet wurde. Wenn local-build? auf wahr steht (wie vorgegeben), wird auf der lokalen Maschine erstellt. options ist eine Liste zusätzlicher Argumente, die an gexp->derivation übergeben werden.

Dies ist das deklarative Gegenstück zu gexp->derivation.

Monadische Prozedur: gexp->script Name Ausdruck [#:guile (default-guile)] [#:module-path %load-path]  [#:system

(%current-system)] [#:target #f] Liefert ein ausführbares Skript namens Name, das den Ausdruck mit dem angegebenen guile ausführt, wobei vom Ausdruck importierte Module in seinem Suchpfad stehen. Die Module des Ausdrucks werden dazu im Modulpfad module-path gesucht.

Folgendes Beispiel erstellt ein Skript, das einfach nur den Befehl ls ausführt:

(use-modules (guix gexp) (gnu packages base))

(gexp->script "list-files"
              #~(execl #$(file-append coreutils "/bin/ls")
                       "ls"))

Lässt man es durch den Store „laufen“ (siehe run-with-store), erhalten wir eine Ableitung, die eine ausführbare Datei /gnu/store/…-list-files generiert, ungefähr so:

#!/gnu/store/…-guile-2.0.11/bin/guile -ds
!#
(execl "/gnu/store/…-coreutils-8.22"/bin/ls" "ls")
Prozedur: program-file Name G-Ausdruck [#:guile #f] [#:module-path %load-path]

Liefert ein Objekt, das eine ausführbare Store-Datei Name repräsentiert, die den G-Ausdruck ausführt. guile ist das zu verwendende Guile-Paket, mit dem das Skript ausgeführt werden kann. Importierte Module des G-Ausdrucks werden im Modulpfad module-path gesucht.

Dies ist das deklarative Gegenstück zu gexp->script.

Monadische Prozedur: gexp->file Name G-Ausdruck [#:set-load-path? #t] [#:module-path %load-path]  [#:splice? #f]  [#:guile

(default-guile)] Liefert eine Ableitung, die eine Datei Name erstellen wird, deren Inhalt der G-Ausdruck ist. Ist splice? wahr, dann wird G-Ausdruck stattdessen als eine Liste von mehreren G-Ausdrücken behandelt, die alle in die resultierende Datei gespleißt werden.

Ist set-load-path? wahr, wird in die resultierende Datei Code hinzugefügt, der den Ladepfad %load-path und den Ladepfad für kompilierte Dateien %load-compiled-path festlegt, die für die importierten Module des G-Ausdrucks nötig sind. Die Module des G-Ausdrucks werden im Modulpfad module-path gesucht.

Die resultierende Datei referenziert alle Abhängigkeiten des G-Ausdrucks oder eine Teilmenge davon.

Prozedur: scheme-file Name Ausdruck [#:splice? #f] [#:set-load-path? #t]

Liefert ein Objekt, das die Scheme-Datei Name mit dem G-Ausdruck als Inhalt repräsentiert.

Dies ist das deklarative Gegenstück zu gexp->file.

Monadische Prozedur: text-file* Name Text

Liefert eine Ableitung als monadischen Wert, welche eine Textdatei erstellt, in der der gesamte Text enthalten ist. Text kann eine Folge nicht nur von Zeichenketten, sondern auch Objekten beliebigen Typs sein, die in einem G-Ausdruck benutzt werden können, also Paketen, Ableitungen, Objekte lokaler Dateien und so weiter. Die resultierende Store-Datei referenziert alle davon.

Diese Variante sollte gegenüber text-file bevorzugt verwendet werden, wann immer die zu erstellende Datei Objekte im Store referenzieren wird. Typischerweise ist das der Fall, wenn eine Konfigurationsdatei erstellt wird, die Namen von Store-Dateien enthält, so wie hier:

(define (profile.sh)
  ;; Liefert den Namen eines Shell-Skripts im Store,
  ;; welcher die Umgebungsvariable „PATH“ initialisiert.
  (text-file* "profile.sh"
              "export PATH=" coreutils "/bin:"
              grep "/bin:" sed "/bin\n"))

In diesem Beispiel wird die resultierende Datei /gnu/store/…-profile.sh sowohl coreutils, grep als auch sed referenzieren, so dass der Müllsammler diese nicht löscht, während die resultierende Datei noch lebendig ist.

Prozedur: mixed-text-file Name Text …

Liefert ein Objekt, was die Store-Datei Name repräsentiert, die Text enthält. Text ist dabei eine Folge von Zeichenketten und dateiartigen Objekten wie zum Beispiel:

(mixed-text-file "profile"
                 "export PATH=" coreutils "/bin:" grep "/bin")

Dies ist das deklarative Gegenstück zu text-file*.

Prozedur: file-union Name Dateien

Liefert ein <computed-file>, das ein Verzeichnis mit allen Dateien enthält. Jedes Objekt in Dateien muss eine zweielementige Liste sein, deren erstes Element der im neuen Verzeichnis zu benutzende Dateiname ist und deren zweites Element ein G-Ausdruck ist, der die Zieldatei benennt. Hier ist ein Beispiel:

(file-union "etc"
            `(("hosts" ,(plain-file "hosts"
                                    "127.0.0.1 localhost"))
              ("bashrc" ,(plain-file "bashrc"
                                     "alias ls='ls --color=auto'"))))

Dies liefert ein Verzeichnis etc, das zwei Dateien enthält.

Prozedur: directory-union Name Dinge

Liefert ein Verzeichnis, was die Vereinigung der Dinge darstellt, wobei Dinge eine Liste dateiartiger Objekte sein muss, die Verzeichnisse bezeichnen. Zum Beispiel:

(directory-union "guile+emacs" (list guile emacs))

Das liefert ein Verzeichnis, welches die Vereinigung der Pakete guile und emacs ist.

Prozedur: file-append Objekt Suffix …

Liefert ein dateiartiges Objekt, das zur Aneinanderreihung von Objekt und Suffix umgeschrieben wird, wobei das Objekt ein herunterbrechbares Objekt und jedes Suffix eine Zeichenkette sein muss.

Betrachten Sie zum Beispiel diesen G-Ausdruck:

(gexp->script "uname-ausfuehren"
              #~(system* #$(file-append coreutils
                                        "/bin/uname")))

Denselben Effekt könnte man erreichen mit:

(gexp->script "uname-ausfuehren"
              #~(system* (string-append #$coreutils
                                        "/bin/uname")))

Es gibt jedoch einen Unterschied, nämlich enthält das resultierende Skript bei file-append tatsächlich den absoluten Dateinamen als Zeichenkette, während im anderen Fall das resultierende Skript einen Ausdruck (string-append …) enthält, der den Dateinamen erst zur Laufzeit zusammensetzt.

Makro: let-system System Rumpf…
Makro: let-system (System Zielsystem) Rumpf…

System an das System binden, für das momentan erstellt wird – z.B. "x86_64-linux" –, während der Rumpf ausgeführt wird.

In der zweiten Form wird zusätzlich das Ziel an das aktuelle Ziel („Target“) bei der Cross-Kompilierung gebunden. Dabei handelt es sich um ein GNU-Tripel wie z.B. "arm-linux-gnueabihf" – oder um #f, wenn nicht cross-kompiliert wird.

let-system zu benutzen, bietet sich dann an, wenn einmal das in den G-Ausdruck gespleißte Objekt vom Zielsystem abhängen sollte, wie in diesem Beispiel:

#~(system*
   #+(let-system system
       (cond ((string-prefix? "armhf-" system)
              (file-append qemu "/bin/qemu-system-arm"))
             ((string-prefix? "x86_64-" system)
              (file-append qemu "/bin/qemu-system-x86_64"))
             (else
              (error "weiß nicht!"))))
   "-net" "user" #$image)
Makro: with-parameters ((Parameter Wert) …) Ausdruck

Mit diesem Makro verhält es sich ähnlich wie mit der parameterize-Form für dynamisch gebundene Parameter (siehe Parameters in Referenzhandbuch zu GNU Guile). Der Hauptunterschied ist, dass es sich erst auswirkt, wenn das vom Ausdruck zurückgelieferte dateiartige Objekt auf eine Ableitung oder ein Store-Objekt heruntergebrochen wird.

Eine typische Anwendung von with-parameters ist, den für ein bestimmtes Objekt geltenden Systemtyp zwingend festzulegen:

(with-parameters ((%current-system "i686-linux"))
  coreutils)

Obiges Beispiel liefert ein Objekt, das der Erstellung von Coreutils für die i686-Architektur entspricht, egal was der aktuelle Wert von %current-system ist.

Prozedur: gexp-input Objekt [Ausgabe] [#:native? #f]

Liefert ein gexp-input-Verbundsobjekt, das für die Ausgabe des dateiartigen Objekts Objekt steht. Dabei legt man mit #:native? fest, ob eine native Erstellung referenziert wird (wie bei ungexp-native) oder nicht.

Diese Prozedur verwendet man, um eine Referenz auf eine bestimmte Ausgabe eines Objekts an eine Prozedur zu übergeben, in der keine Ausgabe ausgewählt wird. Zum Beispiel, wenn Sie diese Prozedur vorliegen haben, die ein dateiartiges Objekt entgegennimmt:

(define (make-symlink Ziel)
  (computed-file "eine-symbolische-verknüpfung"
                 #~(symlink #$Ziel #$output)))

Mit make-symlink wird hier für sich alleine immer auf die Standardausgabe von Ziel verwiesen – also auf die Ausgabe "out" (siehe Pakete mit mehreren Ausgaben.). Um die Prozedur auf z.B. die Ausgabe "lib" des Pakets hwloc verweisen zu lassen, ruft man sie so auf:

(make-symlink (gexp-input hwloc "lib"))

Auch eine Komposition mit Funktionen für dateiartige Objekte ist möglich:

(make-symlink
  (file-append (gexp-input hwloc "lib") "/lib/libhwloc.so"))

Natürlich gibt es zusätzlich zu in „wirtsseitigem“ Code eingebetteten G-Ausdrücken auch Module mit „erstellungsseitig“ nutzbaren Werkzeugen. Um klarzustellen, dass sie dafür gedacht sind, in der Erstellungsschicht benutzt zu werden, bleiben diese Module im Namensraum (guix build …).

Intern werden hochsprachliche, abstrakte Objekte mit ihrem Compiler entweder zu Ableitungen oder zu Store-Objekten heruntergebrochen. Wird zum Beispiel ein Paket heruntergebrochen, bekommt man eine Ableitung, während ein plain-file zu einem Store-Objekt heruntergebrochen wird. Das wird mit der monadischen Prozedur lower-object bewerkstelligt.

Monadische Prozedur: lower-object Objekt [System] [#:target #f] Liefert die Ableitung oder das Store-Objekt, das dem

Objekt für System als Wert in der Store-Monade %store-monad entspricht, cross-kompiliert für das Zieltripel target, wenn target wahr ist. Das Objekt muss ein Objekt sein, für das es einen mit ihm assoziierten G-Ausdruck-Compiler gibt, wie zum Beispiel ein <package>.

Prozedur: gexp->approximate-sexp G-Ausdruck

Es kann gelegentlich nützlich sein, einen G-Ausdruck in einen S-Ausdruck umzuwandeln, weil zum Beispiel manche Prüfer (siehe guix lint aufrufen) einen Blick auf die Erstellungsphasen eines Pakets werfen, um mögliche Fehler zu finden. Diese Umwandlung können Sie mit dieser Prozedur bewerkstelligen. Allerdings kann dabei manche Information verloren gehen. Genauer gesagt werden herunterbrechbare Objekte stillschweigend durch ein beliebiges Objekt ersetzt. Zurzeit ist dieses beliebige Objekt die Liste (*approximate*), aber verlassen Sie sich nicht darauf, dass es so bleibt.


Fußnoten

(23)

Der Begriff Schicht, englisch Stratum, wurde in diesem Kontext von Manuel Serrano et al. in ihrer Arbeit an Hop geprägt. Oleg Kiselyov, der aufschlussreiche Essays und Code zu diesem Thema geschrieben hat, nennt diese Art der Code-Generierung Staging, deutsch etwa Inszenierung bzw. Aufführung.


Nächste: guix repl aufrufen, Vorige: Die Store-Monade, Nach oben: Programmierschnittstelle   [Inhalt][Index]