Suivant: , Précédent: , Monter: Interface de programmation   [Table des matières][Index]


8.6 Phases de construction

Presque tous les systèmes de construction de paquets mettent en œuvre une notion de phase de construction : une séquence d’actions que le système de construction exécute, lorsque vous construisez le paquet, conduisant aux sous-produits installés dans le dépôt. Une exception notable est le trivial-build-system (voir Systèmes de construction) minimaliste.

Comme nous l’avons dit dans la section précédente, ces systèmes de construction fournissent une liste de phases standards. Pour gnu-build-system, les phases de construction principales sont les suivantes :

set-paths

Défini les variables d’environnement de chemins de recherche pour tous les paquets d’entrée, dont PATH (voir Chemins de recherche).

unpack

Décompresse l’archive des sources et se déplace dans l’arborescence des sources fraîchement extraites. Si la source est en fait un répertoire, le copie dans l’arborescence de construction et entre dans ce répertoire.

patch-source-shebangs

Corrige les shebangs (#!) rencontrés dans les fichiers pour qu’ils se réfèrent aux bons noms de fichiers. Par exemple, elle change #!/bin/sh en #!/gnu/store/…-bash-4.3/bin/sh.

configure

Lance le script configure avec un certain nombre d’options par défaut, comme --prefix=/gnu/store/…, ainsi que les options spécifiées par l’argument #:configure-flags.

build

Lance make avec la liste des drapeaux spécifiés avec #:make-flags. Si l’argument #:parallel-build? est vrai (par défaut), construit avec make -j.

check

Lance make check, ou une autre cible spécifiée par #:test-target, à moins que #:tests? #f ne soit passé. Si l’argument #:parallel-tests? est vrai (par défaut), lance make check -j.

install

Lance make install avec les drapeaux listés dans #:make-flags.

patch-shebangs

Corrige les shebangs des fichiers exécutables installés.

strip

Nettoie les symboles de débogage dans les fichiers ELF (à moins que #:strip-binaries? ne soit faux), les copie dans la sortie debug lorsqu’elle est disponible (voir Installer les fichiers de débogage).

validate-runpath

Valide le RUNPATH des binaires ELF, à moins que #:validate-runpath? ne soit faux (voir Systèmes de construction).

Cette étape de validation s’assure que toutes les bibliothèques partagées par les binaires ELF, qui sont listées dans des entrées DT_NEEDED de leur segment PT_DYNAMIC apparaissent dans l’entrée DT_RUNPATH de ce même binaire. En d’autres termes, elle s’assure que lancer ou utiliser ces binaires ne renvoie pas l’erreur « fichier introuvable » à l’exécution. Voir -rpath dans The GNU Linker, pour plus d’informations sur le RUNPATH.

Les autres systèmes de construction ont des phases similaires, avec quelques variations. Par exemple, cmake-build-system a des phases de même nom, mais sa phase configure exécute cmake au lieu de ./configure. D’autres, tels que python-build-system, ont une liste de phases standard totalement différente. Tout ce code s’exécute côté construction : il est évalué lorsque vous construisez réellement le paquet, dans un processus de construction dédié engendré par le démon de construction (voir Invoquer guix-daemon).

Les phases de construction sont représentées sous forme de listes d’associations ou « alists » (voir Listes d’association dans Manuel de référence de GNU Guile) où chaque clé est un symbole pour le nom de la phase et la valeur associée est une procédure qui accepte un nombre arbitraire d’arguments. Par convention, ces procédures reçoivent des informations sur la construction sous la forme de paramètres nommés, qu’elles peuvent utiliser ou ignorer.

Par exemple, voici comment (guix build gnu-build-system) définit %standard-phases, la variable contenant sa liste de phases de construction21 :

;; Les phases de construction de « gnu-build-system ».

(define* (unpack #:key source #:allow-other-keys)
  ;; Extrait l'archive des sources.
  (invoke "tar" "xvf" source))

(define* (configure #:key outputs #:allow-other-keys)
  ;; Exécute le script « configure ». Installe la sortie « out ».
  (let ((out (assoc-ref outputs "out")))
    (invoke "./configure"
            (string-append "--prefix=" out))))

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

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

(define* (install #:allow-other-keys)
  ;; Installe les fichiers sous le préfixe spécifié à « configure ».
  (invoke "make" "install"))

(define %standard-phases
  ;; La liste des phases standard (un certain nombre d'entre elles sont omises
  ;; par souci de concision).  Chaque élément est une paire symbole/procédure.
  (list (cons 'unpack unpack)
        (cons 'configure configure)
        (cons 'build build)
        (cons 'check check)
        (cons 'install install)))

Cela montre comment %standard-phases est défini comme une liste de paires symbole/procédure (voir Pairs dans GNU Guile Reference Manual). La première paire associe le symbole unpack — un nom — à la procédure unpack ; la deuxième paire définit la phase configure de manière similaire, et ainsi de suite. Lors de la construction d’un paquet qui utilise gnu-build-system avec sa liste de phases par défaut, ces phases sont exécutées de manière séquentielle. Vous pouvez voir le nom de chaque phase commencée et terminée dans le journal de construction des paquets que vous construisez.

Examinons maintenant les procédures elles-mêmes. Chacune est définie par define* : #:key énumère les paramètres nommés que la procédure accepte, éventuellement avec une valeur par défaut, et #:allow-other-keys précise que les autres paramètres nommés sont ignorés (voir Optional Arguments dans GNU Guile Reference Manual).

La procédure unpack prend en compte le paramètre source, que le système de compilation utilise pour passer le nom de fichier de l’archive source (ou le répertoire cloné d’un système de contrôle de version), et elle ignore les autres paramètres. La phase configure ne s’intéresse qu’au paramètre outputs, une liste d’association des noms des sorties du paquet avec le nom de leur fichier du dépôt (voir Des paquets avec plusieurs résultats). Elle extrait le nom de fichier de out, la sortie par défaut, et le transmet à ./configure comme préfixe d’installation, ce qui signifie que make install copiera tous les fichiers vers ce répertoire (voir configuration and makefile conventions dans GNU Coding Standards). build et install ignorent tous leurs arguments. check prend en compte l’argument test-target, qui spécifie le nom de la cible du Makefile pour exécuter les tests ; il imprime un message et saute les tests lorsque tests? est faux.

La liste des phases utilisées pour un paquet particulier peut être modifiée avec le paramètre #:phases du système de construction. La modification de l’ensemble des phases de construction se résume à la création d’une nouvelle liste de phases basée sur la liste %standard-phases décrite ci-dessus. On peut faire cela à l’aide des procédures standards qui manipulent des listes d’associations telles que alist-delete (voir SRFI-1 Association Lists dans GNU Guile Reference Manual) ; cependant, il est plus pratique de le faire avec modify-phases (voir modify-phases).

Voici un exemple de définition de paquet qui supprime la phase configure de %standard-phases et insère une nouvelle phase avant la phase build, appelée set-prefix-in-makefile :

(define-public example
  (package
    (name "example")
    ;; other fields omitted
    (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)
              ;; Modify the makefile so that its
              ;; 'PREFIX' variable points to #$output and
              ;; 'XMLLINT' points to the correct path.
              (substitute* "Makefile"
                (("PREFIX =.*")
                 (string-append "PREFIX = " #$output "\n"))
                (("XMLLINT =.*")
                 (string-append "XMLLINT = "
                                (search-input-file inputs "/bin/xmllint")
                                "\n"))))))))))

The new phase that is inserted is written as an anonymous procedure, introduced with lambda*; it looks for the xmllint executable under a /bin directory among the package’s inputs (voir Référence de package). It also honors the outputs parameter we have seen before. Voir Utilitaires de construction, for more about the helpers used by this phase, and for more examples of modify-phases.

Astuce : You can inspect the code associated with a package’s #:phases argument interactively, at the REPL (voir Utiliser Guix de manière interactive).

Keep in mind that build phases are code evaluated at the time the package is actually built. This explains why the whole modify-phases expression above is quoted (it comes after the #~ or hash-tilde): it is staged for later execution. Voir G-Expressions, for an explanation of code staging and the code strata involved.


Notes de bas de page

(21)

Nous présentons une vue simplifiée de ces phases de construction, mais jetez un œil à (guix build gnu-build-system) pour voir tous les détails !


Suivant: Utilitaires de construction, Précédent: Systèmes de construction, Monter: Interface de programmation   [Table des matières][Index]