Siguiente: Sistemas de construcción, Anterior: Definición de paquetes, Subir: Interfaz programática [Índice general][Índice]
Una de las ventajas de Guix es que, dada una definición de paquete, puede derivar fácilmente variantes de dicho paquete—para una versión diferente del origen, con dependencias u opciones de compilación diferentes, diferentes, etcétera. Algunos de estos paquetes personalizados se pueden definir directamente en la línea de ordenes (véase Opciones de transformación de paquetes). Esta sección describe cómo definir variantes de paquetes en código. Esto puede ser útil en «manifiestos» (véase --manifest) y con su propia colleción de paquetes (véase Creación de un canal) entre otros usos.
Como se ha mostrado previamente, los paquetes son objetos de primera clase
del lenguage Scheme. El módulo (guix packages)
proporciona la forma
sintáctica package
para definir nuevos objetos de paquetes
(véase Referencia de package). La forma más fácil de definir una variante de
un paquete es usar la palabra clave inherit
junto a
package
. Esto le permite heredar de una definición de paquete y
modificar únicamente los campos que desee.
Por ejemplo, a partir de la variable hello
, que contiene la
definición de la versión actual de GNU Hello, podría definir de esta
forma una variante para la versión 2.2 (publicada 2006, ¡con solera!):
(use-modules (gnu packages base)) ;para '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"))))))
El ejemplo previo es equivalente a lo que la opción de transformación de
paquetes --with-source realiza. Esencialmente hello-2.2
preserva todos los campos de hello
, excepto version
y
source
, los cuales se modifican. Tenca en cuenta que la variable
original hello
todavía está disponible en el módulo (gnu
packages base)
sin sufrir ningún cambio. Cuando define un paquete
personalizado como este realmente está añadiendo una nueva definición
de paquete; la orignal sigue disponible.
De igual manera puede definir variantes con un conjunto de dependencias
distinto al del paquete original. Por ejemplo, el paquete gdb
predeterminado depende de guile
pero, puesto que es una dependencia
opcional, podría definir una variante que elimina dicha dependencia de este
modo:
(use-modules (gnu packages gdb) ;para 'gdb' (srfi srfi-1)) ;para 'alist-delete' (define gdb-sin-guile (package (inherit gdb) (inputs (alist-delete "guile" (package-inputs gdb)))))
La llamada alist-delete
anterior elimina la tupla del campo
inputs
cuyo primer elemento es "guile"
(véase SRFI-1 Association Lists en GNU Guile Reference Manual).
En ciertos casos encontrará útil escribir funciones («procedimientos» en el
vocabulario de Scheme) que devuelven un paquete en base a ciertos
parámetros. Por ejemplo, considere la biblioteca luasocket
para el
lenguaje de programación Lua. Se desea crear paquetes de luasocket
para las versiones mayores de Lua. Una forma de hacerlo es definir un
procedimiento que recibe un paquete Lua y devuelve un paquete
luasocket
que depende de él:
(define (make-lua-socket name lua) ;; Devuelve un paquete luasocket construido con LUA. (package (name name) (version "3.0") ;; se omiten varios campos (inputs `(("lua" ,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))
En este ejemplo se han definido los paquetes lua5.1-socket
y
lua5.2-socket
llamando a crea-lua-socket
con distintos
parámetros. Véase Procedures en GNU Guile Reference Manual para más
información sobre procedimientos. El hecho de disponer de definiciones
públicas de nivel superior de estos dos paquetes permite que se les haga
referencia desde la línea de órdenes (véase Módulos de paquetes).
Estas son variantes muy simples. Para facilitar esta tarea, el módulo
(guix transformations)
proporciona una interfaz de alto nivel que se
corresponde directamente con las opciones de transformación de paquetes más
sofisticadas (véase Opciones de transformación de paquetes):
Devuelve un procedimiento que, cuando se le proporciona un objeto que construir (paquete, derivación, etc.), aplica las transformaciones especificadas en opciones y devuelve los objetos resultantes. opciones debe ser una lista de pares símbolo/cadena como los siguientes:
((with-branch . "guile-gcrypt=master")
(without-tests . "libgcrypt"))
Cada símbolo nombra una transformación y la cadena correspondiente es el parámetro de dicha transformación.
Por ejemplo, un manifiesto equivalente a esta orden:
guix build guix \ --with-branch=guile-gcrypt=master \ --with-debug-info=zlib
... sería algo parecido a esto:
(use-modules (guix transformations)) (define transforma ;; El procedimiento de transformación del paquete. (options->transformation '((with-branch . "guile-gcrypt=master") (with-debug-info . "zlib")))) (packages->manifest (list (transforma (specification->package "guix"))))
El procedimiento options->transformation
es conveniente, pero quizá
no es tan flexible como pudiese desear. ¿Cómo se ha implementado? Es posible
que ya se haya percatado de que la mayoría de las opciones de transformación
de paquetes van más allá de los cambios superficiales mostrados en los
primeros ejemplos de esta sección: implican reescritura de entradas,
lo que significa que el grafo de dependencias de un paquete se reescribe
sustituyendo entradas específicas por otras.
La reescritura del grafo de dependencias, con el propósito de reemplazar
paquetes del grafo, es implementada por el procedimiento
package-input-rewriting
en (guix packages)
.
Devuelve un procedimiento que, cuando se le pasa un paquete, reemplaza sus dependencias directas e indirectas, incluyendo sus entradas implícitas cuando deep? es verdadero, de acuerdo a reemplazos. reemplazos es una lista de pares de paquetes; el primer elemento de cada par es el paquete a reemplazar, el segundo es el reemplazo.
Opcionalmente, nombre-reescrito es un procedimiento de un parámetro que toma el nombre del paquete y devuelve su nuevo nombre tras la reescritura.
Considere este ejemplo:
(define libressl-en-vez-de-openssl ;; Esto es un procedimiento para reemplazar OPENSSL ;; por LIBRESSL, recursivamente. (package-input-rewriting `((,openssl . ,libressl)))) (define git-con-libressl (libressl-en-vez-de-openssl git))
Aquí primero definimos un procedimiento de reescritura que substituye openssl por libressl. Una vez hecho esto, lo usamos para definir una variante del paquete git que usa libressl en vez de openssl. Esto es exactamente lo que hace la opción de línea de órdenes --with-input (véase --with-input).
La siguiente variante de package-input-rewriting
puede encontrar
paquetes a reemplazar por su nombre en vez de por su identidad.
Devuelve un procedimiento que, proporcionado un paquete, realiza los
reemplazos proporcionados sobre todo el grafo del paquete, incluyendo
las entradas implícitas a menos que deep? sea falso. reemplazos
es una lista de pares de especificación y procedimiento; cada especificación
es una especificación de paquete como "gcc"
o "guile@2"
, y
cada procedimiento toma un paquete que corresponda con la especificación y
devuelve un reemplazo para dicho paquete.
El ejemplo previo podría ser reescrito de esta forma:
(define libressl-en-vez-de-openssl
;; Reemplaza todos los paquetes llamados "openssl" con LibreSSL.
(package-input-rewriting/spec `(("openssl" . ,(const libressl)))))
La diferencia principal en este caso es que, esta vez, los paquetes se
buscan por su especificación y no por su identidad. En otras palabras,
cualquier paquete en el grafo que se llame openssl
será reemplazado.
Un procedimiento más genérico para reescribir el grafo de dependencias de un
paquete es package-mapping
: acepta cambios arbitrarios sobre nodos
del grafo.
Devuelve un procedimiento que, dado un paquete, aplica proc a todos los paquetes de los que depende y devuelve el paquete resultante. El procedimiento para la recursión cuando cortar? devuelve verdadero para un paquete dado. Cuando deep? tiene valor verdadero, proc se aplica también a las entradas implícitas.
Siguiente: Sistemas de construcción, Anterior: Definición de paquetes, Subir: Interfaz programática [Índice general][Índice]