Suivant: Chemins de recherche, Précédent: Phases de construction, Monter: Interface de programmation [Table des matières][Index]
Dès que vous commencerez à écrire des définitions de paquets non triviales
(voir Définition des paquets) ou d’autres actions de compilation
(voir G-Expressions), vous commencerez probablement à chercher des
fonctions auxiliaires pour les actions « de type shell » — créer des
répertoires, copier et supprimer des fichiers de manière récursive,
manipuler les phases de compilation, etc. Le module (guix build
utils)
fournit de telles procédures utilitaires.
La plupart des systèmes de construction chargent (guix build utils)
(voir Systèmes de construction). Ainsi, lorsque vous écrivez des phases de
construction personnalisées pour vos définitions de paquets, vous pouvez
généralement supposer que ces procédures sont disponibles.
Lorsque vous écrivez des G-expressions, vous pouvez importer (guix
build utils)
« côté construction » en utilisant
with-imported-modules
et ensuite le rendre disponible avec la forme
use-modules
(voir Using Guile Modules dans GNU Guile Reference
Manual) :
(with-imported-modules '((guix build utils)) ;on l'importe
(computed-file "empty-tree"
#~(begin
;; On le rend disponible.
(use-modules (guix build utils))
;; On utilise sa procédure « mkdir-p » sans souci.
(mkdir-p (string-append #$output "/a/b/c")))))
Le reste de cette section est la référence pour la plupart des procédures
auxiliaires fournies par (guix build utils)
.
Cette section documente les procédures de traitement des noms de fichier du dépôt.
Renvoie le nom de répertoire du dépôt.
Renvoie vrai si fichier est dans le dépôt.
Enlevez le /gnu/store et le hash de fichier, un nom de fichier
du dépôt. Le résultat est généralement une chaîne
"paquet-version"
.
Si l’on passe nom, un nom de paquet comme "toto-0.9.1b"
, on
obtient deux valeurs : "toto"
et "0.9.1b"
. Lorsque la partie
version est indisponible, nom et #f
sont renvoyés. Le premier
trait d’union suivi d’un chiffre est considéré comme introduisant la partie
version.
Les procédures ci-dessous portent sur les fichiers et les types de fichiers.
Renvoie #t
si dir existe et est un répertoire.
Renvoie #t
si fichier existe et est exécutable.
Renvoie #t
si fichier est un lien symbolique (un « symlink »).
Renvoie #t
si fichier est, respectivement, un fichier ELF, une
archive ar
(telle qu’une bibliothèque statique .a), ou un
fichier gzip.
Si fichier est un fichier gzip, réinitialise son horodatage intégré
(comme avec gzip --no-name
) et renvoie vrai. Sinon, renvoie
#f
. Lorsque keep-mtime? est vrai, conserve la date de
modification de fichier.
Les procédures et macros suivantes permettent de créer, modifier et
supprimer des fichiers. Elles offrent des fonctionnalités comparables à
celles des utilitaires shell courants tels que mkdir -p
,
cp -r
, rm -r
et sed
. Elles complètent
l’interface de système de fichiers étendue, mais de bas niveau, de Guile
(voir POSIX dans GNU Guile Reference Manual).
Exécute corps avec répertoire comme répertoire actuel du processus.
En gros, cette macro change le répertoire actuel en répertoire avant
d’évaluer corps, en utilisant chdir
. (voir Processus dans Manuel de référence de GNU Guile). Elle revient au répertoire
initial à la sortie de la portée dynamique de corps, qu’il s’agisse
d’un retour de procédure normal ou d’une sortie non locale telle qu’une
exception.
Crée le répertoire dir et tous ses ancètres.
Crée répertoire s’il n’existe pas et y copie fichier sous le même nom.
Rend fichier inscriptible pour son propriétaire.
copy-file] [#:keep-mtime? #f] [#:keep-permissions? #t] Copy source directory to destination. Follow symlinks if follow-symlinks? is true; otherwise, just preserve them. Call copy-file to copy regular files. When keep-mtime? is true, keep the modification time of the files in source on those of destination. When keep-permissions? is true, preserve file permissions. Write verbose output to the log port.
Efface récursivement dir, comme rm -rf
, sans les liens
symboliques suivants. Ne suit pas non plus les points de montage, à moins
que follow-mounts? ne soit vrai. Rapporte mais ignore les erreurs.
Remplace regexp dans fichier par la chaîne renvoyée par body. body est évalué avec chaque match-var lié à la sous-expression de regexp positionnelle correspondante. Par exemple :
(substitute* file
(("hello")
"good morning\n")
(("toto([a-z]+)titi(.*)$" all letters end)
(string-append "tata" letters end)))
Ici, chaque fois qu’une ligne de fichier contient hello
, elle
est remplacée par good morning
. Chaque fois qu’une ligne de
fichier correspond à la deuxième regexp, all
est lié à la
correspondance complète, letters
est lié à la première
sous-expression, et end
est lié à la dernière.
Lorsque l’une des match-var est _
, aucune variable n’est liée à
la sous-chaîne de correspondance associée.
Autrement, fichier peut être une liste de noms de fichier, auquel cas ils sont tous sujets aux substitutions.
Faites attention à l’utilisation du $
pour faire correspondre la fin
d’une ligne ; à lui seul, il ne correspondra pas à la fin d’une nouvelle
ligne.
Cette section documente les procédures pour chercher et filtrer des fichiers.
Renvoie un prédicat qui devient vrai lorsqu’on lui passe un nom de fichier dont le nom de base correspond à regexp.
Renvoie la liste des fichiers triés lexicographiquement sous dir pour
lesquels pred renvoie « vrai ». Deux arguments sont passés à
pred : le nom absolu du fichier et son tampon stat ; le prédicat par
défaut renvoie toujours « vrai ». pred peut également être une
expression régulière, auquel cas elle est équivalente à
(file-name-predicate pred)
. stat est utilisé pour
obtenir des informations sur les fichiers ; l’utilisation de lstat
signifie que les liens symboliques ne sont pas suivis. Si
directories? est vrai, alors les répertoires seront également inclus.
Si fail-on-error? est vrai, il lance une exception en cas d’erreur.
Voici quelques exemples où nous supposons que le répertoire actuel est la racine de l’arborescence des sources de Guix :
;; Liste tous les fichiers normaux dans le répertoire actuel. (find-files ".") ⇒ ("./.dir-locals.el" "./.gitignore" …) ;; Liste tous les fichiers .scm sous gnu/services. (find-files "gnu/services" "\\.scm$") ⇒ ("gnu/services/admin.scm" "gnu/services/audio.scm" …) ;; Liste les fichiers ar dans le répertoire actuel. (find-files "." (lambda (file stat) (ar-file? file))) ⇒ ("./libformat.a" "./libstore.a" …)
Renvoie le nom complet du fichier pour programme tel qu’il se trouve
dans $PATH
, ou #f
si programme n’a pas pu être trouvé.
Return the complete file name for name as found in inputs;
search-input-file
searches for a regular file and
search-input-directory
searches for a directory. If name could
not be found, an exception is raised.
Here, inputs must be an association list like inputs
and
native-inputs
as available to build phases (voir Phases de construction).
Here is a (simplified) example of how search-input-file
is used in a
build phase of the wireguard-tools
package:
(add-after 'install 'wrap-wg-quick
(lambda* (#:key inputs outputs #:allow-other-keys)
(let ((coreutils (string-append (assoc-ref inputs "coreutils")
"/bin")))
(wrap-program (search-input-file outputs "bin/wg-quick")
#:sh (search-input-file inputs "bin/bash")
`("PATH" ":" prefix ,(list coreutils))))))
You’ll find handy procedures to spawn processes in this module, essentially
convenient wrappers around Guile’s system*
(voir system*
dans GNU Guile Reference Manual).
Invoke program with the given args. Raise an
&invoke-error
exception if the exit code is non-zero; otherwise
return #t
.
The advantage compared to system*
is that you do not need to check
the return value. This reduces boilerplate in shell-script-like snippets
for instance in package build phases.
Return true if c is an &invoke-error
condition.
Access specific fields of c, an &invoke-error
condition.
Report to port (by default the current error port) about c, an
&invoke-error
condition, in a human-friendly way.
Typical usage would look like this:
(use-modules (srfi srfi-34) ;for 'guard' (guix build utils)) (guard (c ((invoke-error? c) (report-invoke-error c))) (invoke "date" "--imaginary-option")) -| command "date" "--imaginary-option" failed with status 1
Invoke program with args and capture program’s standard
output and standard error. If program succeeds, print nothing and
return the unspecified value; otherwise, raise a &message
error
condition that includes the status code and the output of program.
Here’s an example:
(use-modules (srfi srfi-34) ;for 'guard' (srfi srfi-35) ;for 'message-condition?' (guix build utils)) (guard (c ((message-condition? c) (display (condition-message c)))) (invoke/quiet "date") ;all is fine (invoke/quiet "date" "--imaginary-option")) -| 'date --imaginary-option' exited with status 1; output follows: date: unrecognized option '--imaginary-option' Try 'date --help' for more information.
Le (guix build utils)
contient également des outils permettant de
manipuler les phases de construction telles qu’elles sont utilisées par les
systèmes de construction (voir Systèmes de construction). Les phases de
construction sont représentées sous forme de listes d’associations ou «
alists » (voir Association Lists dans Manuel de référence de GNU
Guile) où chaque clé est un symbole désignant la phase et où la valeur
associée est une procédure (voir Phases de construction).
Le noyau Guile et le module (srfi srfi-1)
fournissent tous deux des
outils pour manipuler les alignements. Le module (guix build utils)
complète ces outils avec des outils écrits en tenant compte des phases de
construction.
Modifie phases séquentiellement selon chaque clause, qui peut avoir l’une des formes suivantes :
(delete old-phase-name) (replace old-phase-name new-phase) (add-before old-phase-name new-phase-name new-phase) (add-after old-phase-name new-phase-name new-phase)
Où chaque phase-name ci-dessus est une expression s’évaluant en un symbole, et new-phase une expression évaluant à une procédure.
L’exemple ci-dessous est tiré de la définition du paquet grep
. Il
ajoute une phase à exécuter après la phase install
, appelée
fix-egrep-and-fgrep
. Cette phase est une procédure (lambda*
pour les procédures anonymes) qui prend un paramètre nommé #:outputs
et ignore les paramètres nommés supplémentaires (voir Optional Arguments dans GNU Guile Reference Manual, pour en savoir plus sur
lambda*
et les arguments optionnels et nommés). La phase utilise
substitute*
pour modifier les scripts egrep et fgrep
installés afin qu’ils se réfèrent à grep
par son nom de fichier
absolu :
(modify-phases %standard-phases
(add-after 'install 'fix-egrep-and-fgrep
;; Patch 'egrep' and 'fgrep' to execute 'grep' via its
;; absolute file name instead of searching for it in $PATH.
(lambda* (#:key outputs #:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
(bin (string-append out "/bin")))
(substitute* (list (string-append bin "/egrep")
(string-append bin "/fgrep"))
(("^exec grep")
(string-append "exec " bin "/grep")))))))
Dans l’exemple ci-dessous, les phases sont modifiées de deux façons : la
phase standard configure
est supprimée, vraisemblablement parce que
le paquet n’a pas de script configure ou quelque chose de similaire,
et la phase par défaut install
est remplacée par une phase qui copie
manuellement les fichiers exécutables à installer :
(modify-phases %standard-phases
(delete 'configure) ;no 'configure' script
(replace 'install
(lambda* (#:key outputs #:allow-other-keys)
;; The package's Makefile doesn't provide an "install"
;; rule so do it by ourselves.
(let ((bin (string-append (assoc-ref outputs "out")
"/bin")))
(install-file "footswitch" bin)
(install-file "scythe" bin)))))
It is not unusual for a command to require certain environment variables to be set for proper functioning, typically search paths (voir Chemins de recherche). Failing to do that, the command might fail to find files or other commands it relies on, or it might pick the “wrong” ones—depending on the environment in which it runs. Examples include:
PATH
;
GUILE_LOAD_PATH
and GUILE_LOAD_COMPILED_PATH
;
QT_PLUGIN_PATH
.
For a package writer, the goal is to make sure commands always work the same
rather than depend on some external settings. One way to achieve that is to
wrap commands in a thin script that sets those environment variables,
thereby ensuring that those run-time dependencies are always found. The
wrapper would be used to set PATH
, GUILE_LOAD_PATH
, or
QT_PLUGIN_PATH
in the examples above.
To ease that task, the (guix build utils)
module provides a couple of
helpers to wrap commands.
variables should look like this:
'(variable delimiter position list-of-directories)
where delimiter is optional. :
will be used if delimiter
is not given.
For example, this call:
(wrap-program "foo"
'("PATH" ":" = ("/gnu/.../bar/bin"))
'("CERT_PATH" suffix ("/gnu/.../baz/certs"
"/qux/certs")))
will copy foo to .foo-real and create the file foo with the following contents:
#!location/of/bin/bash export PATH="/gnu/.../bar/bin" export CERT_PATH="$CERT_PATH${CERT_PATH:+:}/gnu/.../baz/certs:/qux/certs" exec -a $0 location/of/.foo-real "$@"
If program has previously been wrapped by wrap-program
, the
wrapper is extended with definitions for variables. If it is not,
sh will be used as the interpreter.
such that variables are set first. The format of variables is
the same as in the wrap-program
procedure. This procedure differs
from wrap-program
in that it does not create a separate shell
script. Instead, program is modified directly by prepending a Guile
script, which is interpreted as a comment in the script’s language.
Special encoding comments as supported by Python are recreated on the second line.
Note that this procedure can only be used once per file as Guile scripts are not supported.
Suivant: Chemins de recherche, Précédent: Phases de construction, Monter: Interface de programmation [Table des matières][Index]