Suivant: Écrire un manifeste, Précédent: Définition des paquets, Monter: Interface de programmation [Table des matières][Index]
L’une des choses intéressantes avec Guix est qu’à partir d’une définition, on peut facilement dériver des variantes du paquet — pour une version en amont différente, avec des dépendances différentes, des options de compilation différentes, etc. Certains de ces paquets personnalisés peuvent être définis directement par la ligne de commande (voir Options de transformation de paquets). Cette section décrit comment définir des variantes de paquets avec du code. Cela est utile dans les « manifestes » (voir Écrire un manifeste) et dans votre propre collection de paquets (voir Écrire de nouveaux de canaux), entre autres choses !
Comme nous en avons parlé plus tôt, les paquets sont des objets de première
classe dans le langage Scheme. Le module (guix packages)
fournit la
construction package
pour définir de nouveaux objets de paquets
(voir Référence de package
). La manière la plus simple de définir la
variante d’un paquet est d’utiliser le mot-clé inherit
avec
package
. Cela vous permet d’hériter la définition d’un paquet tout
en redéfinissant les champs que vous voulez.
Par exemple, étant donné la variable hello
, qui contient la
définition d’une version récente de GNU Hello, voici comment définir
une variante pour la version 2.2 (publiée en 2006, c’est vintage !) :
(use-modules (gnu packages base)) ;pour 'hello' (define hello-2.2 (package (inherit hello) (version "2.2") (source (origin (method url-fetch) (uri (string-append "mirror://gnu/hello/hello-" version ".tar.gz")) (sha256 (base32 "0lappv4slgb5spyqbh6yl5r013zv72yqg2pcl30mginf3wdqd8k9"))))))
L’exemple ci-dessus correspond à ce que font les options de transformation
des paquets --with-version et --with-source. En
substance, hello-2.2
préserve tous les champs de hello
, sauf
version
et source
, qu’il remplace. Remarquez que la variable
hello
originale est toujours là, dans le module (gnu packages
base)
, et n’est pas modifiée. Lorsque vous définissez un paquet
personnalisé comme ceci, vous ajoutez en fait une nouvelle définition
de paquet ; la version originale est toujours disponible.
Vous pouvez aussi bien définir des variantes avec un ensemble de dépendances
différent du paquet d’origine. Par exemple, le paquet gdb
par défaut
dépend de guile
, mais comme c’est une dépendance facultative, vous
pouvez définir une variante qu supprime cette dépendance de cette manière :
(use-modules (gnu packages gdb)) ; pour « gdb » (define gdb-sans-guile (package (inherit gdb) (inputs (modify-inputs (package-inputs gdb) (delete "guile")))))
La forme modify-inputs
ci-dessus supprime le paquet "guile"
du
champ inputs
de gdb
. La macro modify-inputs
est une
macro auxiliaire qui peut être utile si vous voulez supprimer, ajouter et
remplacer des paquets en entrée.
Modifie les entrées de paquet spécifiées, telles que renvoyées par
package-inputs
& co., suivant les clauses données. Chaque clause
doit avoir l’une des formes suivantes :
(delete nom…)
Supprime des entrées les paquets avec les noms donnés (chaines de caractères).
(prepend paquet…)
Ajoute les paquets au début de la liste des entrées.
(append paquet…)
Ajoute les paquets à la fin de la liste des entrées.
(replace name replacement)
Replace the package called name with replacement.
L’exemple suivant supprime les entrées GMP et ACL de Coreutils et ajoute libcap au début de la liste des entrées :
(modify-inputs (package-inputs coreutils)
(delete "gmp" "acl")
(prepend libcap))
L’exemple suivant remplace le paquet guile
des entrées de
guile-redis
avec guile-2.2
:
(modify-inputs (package-inputs guile-redis)
(replace "guile" guile-2.2))
Le dernier type de clause est append
, pour ajouter des entrées à la
fin de la liste.
Dans certains cas, vous pouvez trouver cela utile d’écrire des fonctions («
procédures », pour Scheme) qui renvoie un paquet en fonction de certains
paramètres. Par exemple, considérez la bibliothèque luasocket
pour
le langage de programmation lua. Nous voulons créer des paquets
luasocket
pour les versions majeures de Lua. Une manière de faire
est de définir une procédure qui prend un paquet Lua et renvoie un paquet
luasocket
qui en dépend :
(define (make-lua-socket name lua) ;; Renvoie un paquet luasocket construit avec LUA. (package (name name) (version "3.0") ;; plusieurs champs ont été omis (inputs (list lua)) (synopsis "Socket library for Lua"))) (define-public lua5.1-socket (make-lua-socket "lua5.1-socket" lua-5.1)) (define-public lua5.2-socket (make-lua-socket "lua5.2-socket" lua-5.2))
ici nous avons défini les paquets lua5.1-socket
et
lua5.2-socket
en appelant make-lua-socket
avec différents
arguments. Voir Procedures dans GNU Guile Reference Manual, pour
plus d’informations sur les procédures. Avoir des définitions publiques au
premier niveau pour ces deux paquets signifie qu’ils sont disponibles depuis
la ligne de commande (voir Modules de paquets).
Ce sont des variantes simples de paquets. Par simplicité, le module
(guix transformations)
fournit une interface de haut niveau qui
correspond directement aux options de transformations de paquets plus
sophistiquées (voir Options de transformation de paquets) :
Renvoie une procédure qui, lorsqu’on lui passe un objet à construire (un paquet, une dérivation, etc), applique les transformations spécifiées par opts et renvoie les objets qui en résultent. opts doit être une liste de pairs de symboles et de chaine comme dans :
((with-branch . "guile-gcrypt=master")
(without-tests . "libgcrypt"))
Chaque nom de symbole nomme une transformation et la chaine correspondante est un argument pour cette transformation.
Par exemple, un manifeste équivalent à cette commande :
guix build guix \ --with-branch=guile-gcrypt=master \ --with-debug-info=zlib
... ressemblerait à ceci :
(use-modules (guix transformations)) (define transform ;; La procédure de transformation des paquets. (options->transformation '((with-branch . "guile-gcrypt=master") (with-debug-info . "zlib")))) (packages->manifest (list (transform (specification->package "guix"))))
La procédure options->transformation
est pratique, mais elle n’est
peut-être pas aussi flexible que vous pourriez le souhaiter. Comment
est-elle implémentée ? Le lecteur attentif aura sans doute remarqué que la
plupart des options de transformation des paquets va plus loin que les
changements superficiels montrés dans les premiers exemples de cette
sections : ils font de la réécriture d’entrées, où le graphe de
dépendance d’un paquet est réécrit en remplaçant des entrées spécifiques par
d’autres.
La procédure package-input-rewriting
de (guix packages)
implémente la réécriture du graphe de dépendance, pour remplacer des paquets
dans le graphe.
Renvoie une procédure qui, lorsqu’elle est passée à un paquet, remplace ses dépendances directes et indirectes, y compris les entrées implicites lorsque deep? est vrai, selon replacements. replacements est une liste de paires de paquets ; le premier élément de chaque paire est le paquet à remplacer, et le second est le remplacement.
De manière facultative, nom-réécrit est une procédure à un argument qui prend le nom d’un paquet et renvoie son nouveau nom après l’avoir réécrit.
Regardez cet exemple :
(define libressl-instead-of-openssl ;; Cette procédure remplace OPENSSL par LIBRESSL, ;; récursivement. (package-input-rewriting `((,openssl . ,libressl)))) (define git-with-libressl (libressl-instead-of-openssl git))
Ici nous définissons d’abord une procédure de réécriture qui remplace openssl par libressl. Ensuite nous l’utilisons pour définir une variante du paquet git qui utilise libressl plutôt que openssl. cela est exactement ce que l’option en ligne de commande --with-input fait (voir --with-input).
La variante suivante de package-input-rewriting
peut repérer les
paquets à remplacer par nom à la place de leur identité.
Renvoie une procédure qui, étant donné un paquet, applique les remplacements donnés à tout le graphe du paquet, y compris les entrées implicites, à moins que deep? ne soit faux.
replacements is a list of spec/procedures pair; each spec is a package
specification such as "gcc"
or "guile@2"
, and each procedure
takes a matching package and returns a replacement for that package.
Matching packages that have the hidden?
property set are not
replaced.
L’exemple ci-dessus pourrait être réécrit de cette manière :
(define libressl-instead-of-openssl
;; Remplace tous les paquets nommés « openssl » par LibreSSL.
(package-input-rewriting/spec `(("openssl" . ,(const libressl)))))
Le différence clef est que, cette fois-ci, les paquets correspondent à la
spécification et non à l’identité. En d’autres termes, tout paquet dans le
graphe qui est appelé openssl
sera remplacé.
Une procédure plus générique pour réécrire un graphe de dépendance d’un
paquet est package-mapping
: elle supporte n’importe quel changement
dans les nœuds du graphe.
Renvoie une procédure qui, pour un paquet donné, applique proc à tous les paquets dont il dépend et renvoie le paquet résultant. La procédure arrête la récursion lorsque cut? renvoie true pour un paquet donné. Lorsque deep? est vrai, proc est également appliqué aux entrées implicites.
Tips : Understanding what a variant really looks like can be difficult as one starts combining the tools shown above. There are several ways to inspect a package before attempting to build it that can prove handy:
- You can inspect the package interactively at the REPL, for instance to view its inputs, the code of its build phases, or its configure flags (voir Utiliser Guix de manière interactive).
- When rewriting dependencies,
guix graph
can often help visualize the changes that are made (voir Invoqueguix graph
).
Suivant: Écrire un manifeste, Précédent: Définition des paquets, Monter: Interface de programmation [Table des matières][Index]