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


8.6 Erstellungsphasen

Fast alle Erstellungssysteme für Pakete implementieren ein Konzept von Erstellungsphasen: einer Abfolge von Aktionen, die vom Erstellungssystem ausgeführt werden, wenn Sie das Paket erstellen. Dabei fallen in den Store installierte Nebenerzeugnisse an. Eine Ausnahme ist der Erwähnung wert: das magere trivial-build-system (siehe Erstellungssysteme).

Wie im letzten Abschnitt erläutert, stellen diese Erstellungssysteme eine standardisierte Liste von Phasen zur Verfügung. Für gnu-build-system sind dies die hauptsächlichen Erstellungsphasen:

set-paths

Suchpfade in Umgebungsvariablen definieren. Dies geschieht für alle Eingabepakete. PATH wird so auch festgelegt. Siehe Suchpfade.

unpack

Den Quell-Tarball entpacken und das Arbeitsverzeichnis wechseln in den entpackten Quellbaum. Wenn die Quelle bereits ein Verzeichnis ist, wird es in den Quellbaum kopiert und dorthin gewechselt.

patch-source-shebangs

„Shebangs“ in Quelldateien beheben, damit Sie sich auf die richtigen Store-Dateipfade beziehen. Zum Beispiel könnte #!/bin/sh zu #!/gnu/store/…-bash-4.3/bin/sh geändert werden.

configure

Das Skript configure mit einigen vorgegebenen Befehlszeilenoptionen ausführen, wie z.B. mit --prefix=/gnu/store/…, sowie mit den im #:configure-flags-Argument angegebenen Optionen.

build

make ausführen mit den Optionen aus der Liste in #:make-flags. Wenn das Argument #:parallel-build? auf wahr gesetzt ist (was der Vorgabewert ist), wird make -j zum Erstellen ausgeführt.

check

make check (oder statt check ein anderes bei #:test-target angegebenes Ziel) ausführen, außer falls #:tests? #f gesetzt ist. Wenn das Argument #:parallel-tests? auf wahr gesetzt ist (der Vorgabewert), führe make check -j aus.

install

make install mit den in #:make-flags aufgelisteten Optionen ausführen.

patch-shebangs

Shebangs in den installierten ausführbaren Dateien beheben.

strip

Symbole zur Fehlerbehebung aus ELF-Dateien entfernen (außer #:strip-binaries? ist auf falsch gesetzt) und in die debug-Ausgabe kopieren, falls diese verfügbar ist (siehe Dateien zur Fehlersuche installieren).

validate-runpath

Den RUNPATH von ELF-Binärdateien validieren, sofern #:validate-runpath? falsch ist (siehe Erstellungssysteme).

Die Validierung besteht darin, sicherzustellen, dass jede gemeinsame Bibliothek, die von einer ELF-Binärdatei gebraucht wird (sie sind in DT_NEEDED-Einträgen im PT_DYNAMIC-Segment der ELF-Datei aufgeführt), im DT_RUNPATH-Eintrag der Datei gefunden wird. Mit anderen Worten wird gewährleistet, dass es beim Ausführen oder Benutzen einer solchen Binärdatei nicht zur Laufzeit zu einem Fehler kommt, eine Datei würde nicht gefunden. Siehe -rpath in The GNU Linker für mehr Informationen zum RUNPATH.

Andere Erstellungssysteme haben ähnliche, aber etwas unterschiedliche Phasen. Zum Beispiel hat das cmake-build-system gleichnamige Phasen, aber seine configure-Phase führt cmake statt ./configure aus. Andere Erstellungssysteme wie z.B. python-build-system haben eine völlig andere Liste von Standardphasen. Dieser gesamte Code läuft erstellungsseitig: Er wird dann ausgewertet, wenn Sie das Paket wirklich erstellen, in einem eigenen Erstellungprozess nur dafür, den der Erstellungs-Daemon erzeugt (siehe Aufruf von guix-daemon).

Erstellungsphasen werden durch assoziative Listen (kurz „Alists“) repräsentiert (siehe Association Lists in Referenzhandbuch zu GNU Guile) wo jeder Schlüssel ein Symbol für den Namen der Phase ist und der assoziierte Wert eine Prozedur ist, die eine beliebige Anzahl von Argumenten nimmt. Nach Konvention empfangen diese Prozeduren dadurch Informationen über die Erstellung in Form von Schlüsselwort-Parametern, die darin benutzt oder ignoriert werden können.

Zum Beispiel werden die %standard-phases, das ist die Variable mit der Alist der Erstellungsphasen, in (guix build gnu-build-system) so definiert21:

;; Die Erstellungsphasen von 'gnu-build-system'.

(define* (unpack #:key source #:allow-other-keys)
  ;; Quelltarball extrahieren.
  (invoke "tar" "xvf" source))

(define* (configure #:key outputs #:allow-other-keys)
  ;; 'configure'-Skript ausführen. In Ausgabe "out" installieren.
  (let ((out (assoc-ref outputs "out")))
    (invoke "./configure"
            (string-append "--prefix=" out))))

(define* (build #:allow-other-keys)
  ;; Kompilieren.
  (invoke "make"))

(define* (check #:key (test-target "check") (tests? #true)
                #:allow-other-keys)
  ;; Testkatalog ausführen.
  (if tests?
      (invoke "make" test-target)
      (display "test suite not run\n")))

(define* (install #:allow-other-keys)
  ;; Dateien ins bei 'configure' festgelegte Präfix installieren.
  (invoke "make" "install"))

(define %standard-phases
  ;; Die Liste der Standardphasen (der Kürze halber lassen wir einige
  ;; aus). Jedes Element ist ein Paar aus Symbol und Prozedur.
  (list (cons 'unpack unpack)
        (cons 'configure configure)
        (cons 'build build)
        (cons 'check check)
        (cons 'install install)))

Hier sieht man wie %standard-phases als eine Liste von Paaren aus Symbol und Prozedur (siehe Pairs in Referenzhandbuch zu GNU Guile) definiert ist. Das erste Paar assoziiert die unpack-Prozedur mit dem unpack-Symbol – es gibt einen Namen an. Das zweite Paar definiert die configure-Phase auf ähnliche Weise, ebenso die anderen. Wenn ein Paket erstellt wird, das gnu-build-system benutzt, werden diese Phasen der Reihe nach ausgeführt. Sie können beim Erstellen von Paketen im Erstellungsprotokoll den Namen jeder gestarteten und abgeschlossenen Phase sehen.

Schauen wir uns jetzt die Prozeduren selbst an. Jede davon wird mit define* definiert, dadurch können bei #:key die Schlüsselwortparameter aufgelistet werden, die die Prozedur annimmt, wenn gewünscht auch zusammen mit einem Vorgabewert, und durch #:allow-other-keys wird veranlasst, dass andere Schlüsselwortparameter ignoriert werden (siehe Optional Arguments in Referenzhandbuch zu GNU Guile).

Die unpack-Prozedur berücksichtigt den source-Parameter; das Erstellungssystem benutzt ihn, um den Dateinamen des Quell-Tarballs (oder des Checkouts aus einer Versionskontrolle) zu finden. Die anderen Parameter ignoriert sie. Die configure-Phase interessiert sich nur für den outputs-Parameter, eine Alist, die die Namen von Paketausgaben auf ihre Dateinamen im Store abbildet (siehe Pakete mit mehreren Ausgaben.). Sie extrahiert den Dateinamen für out, die Standardausgabe, und gibt ihn an ./configure als das Installationspräfix weiter, wodurch make install zum Schluss alle Dateien in dieses Verzeichnis kopieren wird (siehe configuration and makefile conventions in GNU Coding Standards). build und install ignorieren all ihre Argumente. check berücksichtigt das Argument test-target, worin der Name des Makefile-Ziels angegeben wird, um die Tests auszuführen. Es wird stattdessen eine Nachricht angezeigt und die Tests übersprungen, wenn tests? falsch ist.

Die Liste der Phasen, die für ein bestimmtes Paket benutzt werden, kann über den #:phases-Parameter an das Erstellungssystem geändert werden. Das Ändern des Satzes von Erstellungsphasen funktioniert so, dass eine neue Alist von Phasen aus der oben beschriebenen %standard-phases-Alist heraus erzeugt wird. Dazu können die Standardprozeduren zur Bearbeitung von assoziativen Listen wie alist-delete benutzt werden (siehe SRFI-1 Association Lists in Referenzhandbuch zu GNU Guile), aber es ist bequemer, dafür die Prozedur modify-phases zu benutzen (siehe modify-phases).

Hier ist ein Beispiel für eine Paketdefinition, die die configure-Phase aus %standard-phases entfernt und eine neue Phase vor der build-Phase namens set-prefix-in-makefile einfügt:

(define-public beispiel
  (package
    (name "beispiel")
    ;; wir lassen die anderen Felder aus
    (build-system gnu-build-system)
    (arguments
     (list
      #:phases
      #~(modify-phases %standard-phases
          (delete 'configure)
          (add-before 'build 'set-prefix-in-makefile
            (lambda* (#:key inputs #:allow-other-keys)
              ;; Makefile anpassen, damit die 'PREFIX'-
              ;; Variable auf #$output verweist und
              ;; 'XMLLINT' auf den richtigen Pfad verweist.
              (substitute* "Makefile"
                (("PREFIX =.*")
                 (string-append "PREFIX = " #$output "\n"))
                (("XMLLINT =.*")
                 (string-append "XMLLINT = "
                                (search-input-file inputs "/bin/xmllint")
                                "\n"))))))))))

Die neu eingefügte Phase wurde als anonyme Prozedur geschrieben. Solche namenlosen Prozeduren schreibt man mit lambda*. Durch sie wird nach der ausführbaren Datei xmllint in jedem Verzeichnis /bin aller Paketeingaben gesucht (siehe package-Referenz). Oben berücksichtigt sie den outputs-Parameter, den wir zuvor gesehen haben. Siehe Werkzeuge zur Erstellung für mehr Informationen über die in dieser Phase benutzten Hilfsmittel und für mehr Beispiele zu modify-phases.

Tipp: You can inspect the code associated with a package’s #:phases argument interactively, at the REPL (siehe Interaktiv mit Guix arbeiten).

Sie sollten im Kopf behalten, dass Erstellungsphasen aus Code bestehen, der erst dann ausgewertet wird, wenn das Paket erstellt wird. Das ist der Grund, warum der gesamte modify-phases-Ausdruck oben quotiert wird. Quotiert heißt, er steht nach einem ' oder Apostrophenzeichen: Er wird nicht sofort als Code ausgewertet, sondern nur zur späteren Ausführung vorgemerkt (wir sagen staged, siehe G-Ausdrücke für eine Erläuterung von Code-Staging und den beteiligten Code-Schichten (oder „Strata“).


Fußnoten

(21)

Wir stellen hier nur eine vereinfachte Sicht auf diese Erstellungsphasen vor. Wenn Sie alle Details wollen, schauen Sie sich (guix build gnu-build-system) an!


Nächste: Werkzeuge zur Erstellung, Vorige: Erstellungssysteme, Nach oben: Programmierschnittstelle   [Inhalt][Index]