Ricettario di GNU Guix

Successivo: , Su: (dir) [Contenuti][Indice]

Ricettario di GNU Guix

Questo documento presenta tutorial ed esempi dettagliati per GNU Guix, uno strumento di gestione pacchetti funzionale scritto per il sistema GNU. Si prega di vedi manuale di riferimento di GNU Guix per dettagli sul sistema, la sua API e i concetti correlati.

Questo manuale è disponibile anche in inglese (vedi GNU Guix Cookbook ), francese (vedi Livre de recettes de GNU Guix ), cinese semplificato (vedi GNU Guix 烹饪书 ), tedesco (vedi GNU-Guix-Kochbuch ), coreano (vedi GNU Guix 쿡북 ), spagnolo (vedi Libro de recetas de GNU Guix ), portoghese brasiliano (vedi Livro de receitas do GNU Guix ), russo (vedi GNU Guix Рецепты ), slovacco (vedi Receptár GNU Guix ) e svedese (vedi Kokbok för GNU Guix ). Se desideri tradurre questo documento nella tua lingua madre, considera di unirti a Weblate (vedi Tradurre Guix in Manuale di riferimento di GNU Guix).

Indice


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

1 Tutorial di Scheme

GNU Guix è scritto nel linguaggio di programmazione generico Scheme, e molte delle sue funzionalità possono essere accessibili e manipolate programmaticamente. Puoi usare Scheme per generare definizioni di pacchetti, per modificarle, per compilarle, per distribuire interi sistemi operativi, ecc.

Conoscere le basi di come programmare in Scheme sbloccherà molte delle funzionalità avanzate che Guix fornisce — e non è nemmeno necessario essere un programmatore esperto per usarle!

Iniziamo!


Su: Tutorial di Scheme [Contenuti][Indice]

1.1 Un corso intensivo di Scheme

Guix utilizza l’implementazione Guile di Scheme. Per iniziare a giocare con il linguaggio, installalo con guix install guile e avvia un REPL — abbreviazione di read-eval-print loop — eseguendo guile dalla riga di comando.

In alternativa, puoi anche eseguire guix shell guile -- guile se preferisci non avere Guile installato nel tuo profilo utente.

Negli esempi seguenti, le righe mostrano cosa digiteresti nel REPL; le righe che iniziano con "⇒" mostrano i risultati della valutazione, mentre le righe che iniziano con "-|" mostrano le cose che vengono stampate. Vedi Using Guile Interactively in Manuale di riferimento di GNU Guile, per maggiori dettagli sul REPL.

  • La sintassi di Scheme si riduce a un albero di espressioni (o s-expression nel gergo Lisp). Un’espressione può essere un letterale come numeri e stringhe, o un composto che è una lista tra parentesi di composti e letterali. #true e #false (abbreviato #t e #f) rappresentano i booleani "vero" e "falso", rispettivamente.

    Esempi di espressioni valide:

    "Hello World!"
     "Hello World!"
    17
     17
    (display (string-append "Ciao " "Guix" "\n"))
    -| Ciao Guix!
     #<unspecified>
    
  • Quest’ultimo esempio è una chiamata di funzione annidata in un’altra chiamata di funzione. Quando un’espressione tra parentesi viene valutata, il primo termine è la funzione e il resto sono gli argomenti passati alla funzione. Ogni funzione restituisce l’ultima espressione valutata come valore di ritorno.
  • Le funzioni anonime — procedures nel gergo di Scheme — sono dichiarate con il termine lambda:
    (lambda (x) (* x x))
     #<procedure 120e348 at <unknown port>:24:0 (x)>
    

    La procedura sopra restituisce il quadrato del suo argomento. Poiché tutto è un’espressione, l’espressione lambda restituisce una procedura anonima, che a sua volta può essere applicata a un argomento:

    ((lambda (x) (* x x)) 3)
     9
    

    Le procedure sono valori regolari proprio come numeri, stringhe, booleani e così via.

  • A qualsiasi cosa può essere assegnato un nome globale con define:
    (define a 3)
    (define square (lambda (x) (* x x)))
    (square a)
     9
    
  • Le procedure possono essere definite in modo più conciso con la seguente sintassi:
    (define (square x) (* x x))
    
  • Una struttura di lista può essere creata con la procedura list:
    (list 2 a 5 7)
     (2 3 5 7)
    
  • Le procedure standard sono fornite dal modulo (srfi srfi-1) per creare ed elaborare liste (vedi elaborazione di liste in Manuale di riferimento di GNU Guile). Ecco alcune delle più utili in azione:
    (use-modules (srfi srfi-1)) ;importa procedure di elaborazione di liste
    
    (append (list 1 2) (list 3 4))
     (1 2 3 4)
    (map (lambda (x) (* x x)) (list 1 2 3 4))
     (1 4 9 16)
    (delete 3 (list 1 2 3 4))  (1 2 4)
    (filter odd? (list 1 2 3 4))  (1 3)
    (remove even? (list 1 2 3 4))  (1 3)
    (find number? (list "a" 42 "b"))  42
    

    Notare come il primo argomento di map, filter, remove e find sia una procedura!

  • Il quote disabilita la valutazione di un’espressione tra parentesi, chiamata anche S-expression o "s-exp": il primo termine non viene chiamato sugli altri termini (vedi quote in Manuale di riferimento di GNU Guile). Quindi restituisce effettivamente una lista di termini.
    '(display (string-append "Ciao " "Guix" "\n"))
     (display (string-append "Ciao " "Guix" "\n"))
    '(2 a 5 7)
     (2 a 5 7)
    
  • Il quasiquote (`, un apice inverso) disabilita la valutazione di un’espressione tra parentesi finché unquote (,, una virgola) non la riabilita. Quindi ci fornisce un controllo preciso su cosa viene valutato e cosa no.
    `(2 a 5 7 (2 ,a 5 ,(+ a 4)))
     (2 a 5 7 (2 3 5 7))
    

    Notare che il risultato sopra è una lista di elementi misti: numeri, simboli (qui a) e l’ultimo elemento è una lista stessa.

  • Guix definisce una variante delle S-expression con gli steroidi chiamata G-expressions o "gexps", che viene fornita con una variante di quasiquote e unquote: #~ (o gexp) e #$ (o ungexp). Ti permettono di mettere in scena il codice per un’esecuzione successiva.

    Ad esempio, incontrerai le gexps in alcune definizioni di pacchetto dove forniscono codice da eseguire durante il processo di compilazione del pacchetto. Appaiono così:

    (use-modules (guix gexp) ;così possiamo scrivere gexps
     (gnu packages base)) ;per 'coreutils'
    
    ;; Di seguito una G-expression che rappresenta codice messo in scena.
    #~(begin
     ;; Invoca 'ls' dal package definito dalla variabile 'coreutils'.
     (system* #$(file-append coreutils "/bin/ls") "-l")
     ;; Crea la directory di output di questo pacchetto.
     (mkdir #$output))
    

    Vedi G-expression in Manuale di riferimento di GNU Guix, per maggiori informazioni sulle gexps.

  • È possibile nominare più variabili localmente con let (vedi Local Bindings in Manuale di Riferimento di GNU Guile):
    (define x 10)
    (let ((x 2)
     (y 3))
     (list x y))
     (2 3)
    x
     10
    y
    error→ In procedure module-lookup: Variabile non legata: y
    

    Usa let* per permettere alle dichiarazioni di variabili successive di fare riferimento a definizioni precedenti.

    (let* ((x 2)
     (y (* x 3)))
     (list x y))
     (2 6)
    
  • Le Parole Chiave sono tipicamente usate per identificare i parametri nominati di una procedura. Sono precedute da #: (cancelletto, due punti) seguito da caratteri alfanumerici: #:in-questo-modo. Vedi Keywords in Manuale di riferimento di GNU Guile.
  • La percentuale % è tipicamente usata per le variabili globali di sola lettura nella fase di compilazione. Notare che è solo una convenzione, come _ in C. Scheme tratta % esattamente come qualsiasi altra lettera.
  • I moduli sono creati con define-module (vedi Creating Guile Modules in Manuale di riferimento di GNU Guile). Per esempio
    (define-module (guix build-system ruby)
     #:use-module (guix store)
     #:export (ruby-build
     ruby-build-system ))
    

    definisce il modulo guix build-system ruby che deve essere situato in guix/build-system/ruby.scm da qualche parte nel percorso di caricamento di Guile. Dipende dal modulo (guix store) ed esporta due variabili, ruby-build e ruby-build-system.

    Vedi Moduli di pacchetti in Manuale di riferimento di GNU Guix, per informazioni sui moduli che definiscono i pacchetti.

Andare oltre: Scheme è un linguaggio ampiamente utilizzato per insegnare la programmazione e troverai molto materiale che lo usa come veicolo. Ecco una selezione di documenti per saperne di più su Scheme:

Troverai altri libri, tutorial e altre risorse su https://schemers.org/.


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

2 Impacchettamento

Questo capitolo è dedicato a insegnarti come aggiungere pacchetti alla collezione di pacchetti fornita con GNU Guix. Ciò comporta la scrittura di definizioni di pacchetti in Guile Scheme, l’organizzazione in moduli di pacchetti e la loro compilazione.


Successivo: , Su: Impacchettamento [Contenuti][Indice]

2.1 Tutorial sull’Impacchettamento

GNU Guix si distingue come il gestore di pacchetti hackable, principalmente perché utilizza GNU Guile, un potente linguaggio di programmazione di alto livello, uno dei dialetti Scheme della famiglia Lisp.

Anche le definizioni dei pacchetti sono scritte in Scheme, il che conferisce a Guix poteri unici, a differenza della maggior parte degli altri gestori di pacchetti che utilizzano script di shell o linguaggi semplici.

  • Usa funzioni, strutture, macro e tutta l’espressività di Scheme per le tue definizioni di pacchetto.
  • L’ereditarietà rende facile personalizzare un pacchetto ereditando da esso e modificando solo ciò che è necessario.
  • Elaborazione batch: l’intera collezione di pacchetti può essere analizzata, filtrata ed elaborata. Costruire un server headless con tutte le interfacce grafiche rimosse? È possibile. Vuoi ricompilare tutto dal sorgente usando flag di ottimizzazione del compilatore specifici? Passa l’argomento #:make-flags "..." alla lista dei pacchetti. Non sarebbe un’esagerazione pensare ai flag USE di Gentoo qui, ma questo va anche oltre: le modifiche non devono essere pensate in anticipo dal manutentore del pacchetto, possono essere programmed dall’utente!

Il seguente tutorial copre tutte le basi sulla creazione di pacchetti con Guix. Non presuppone molta conoscenza del sistema Guix né del linguaggio Lisp. Si presume che il lettore abbia familiarità con la riga di comando e abbia alcune conoscenze di programmazione di base.


2.1.1 Un pacchetto "Hello World"

La sezione "Definire i pacchetti" del manuale introduce le basi dell’impacchettamento con Guix (vedi Definire i pacchetti in Manuale di riferimento di GNU Guix). Nella sezione seguente, ripercorreremo in parte queste basi.

GNU Hello è un progetto fittizio che serve come esempio idiomatico per l’impacchettamento. Utilizza il sistema di compilazione GNU (./configure && make && make install). Guix fornisce già una definizione di pacchetto che è un esempio perfetto da cui partire. Puoi consultare la sua dichiarazione con guix edit hello dalla riga di comando. Vediamo come appare:

(define-public hello
 (package
 (name "hello")
 (version "2.10")
 (source (origin
 (method url-fetch )
 (uri (string-append "mirror://gnu/hello/hello-" version
 ".tar.gz"))
 (sha256
 (base32
 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
 (build-system gnu-build-system )
 (synopsis "Ciao, mondo GNU: Un esempio di pacchetto GNU")
 (description
 "GNU Hello stampa il messaggio \"Ciao, mondo!\" e poi esce. Serve come esempio di pratiche di codifica standard GNU. Come tale, supporta argomenti da riga di comando, più lingue, e così via.")
 (home-page "https://www.gnu.org/software/hello/")
 (license gpl3+)))

Come puoi vedere, la maggior parte è piuttosto semplice. Ma esaminiamo i campi insieme:

name

Il nome del progetto. Usando le convenzioni di Scheme, preferiamo mantenerlo in minuscolo, senza trattini bassi e usando parole separate da trattini.

source

Questo campo contiene una descrizione dell’origine del codice sorgente. Il record origin contiene questi campi:

  1. Il metodo, qui url-fetch per scaricare via HTTP/FTP, ma altri metodi esistono, come git-fetch per i repository Git.
  2. L’URI, che è tipicamente una posizione https:// per url-fetch. Qui lo speciale ‘mirror://gnu‘ si riferisce a un insieme di posizioni note, tutte utilizzabili da Guix per recuperare il sorgente, nel caso in cui alcune di esse fallissero.
  3. La somma di controllo sha256 del file richiesto. Questo è essenziale per garantire che il sorgente non sia corrotto. Notare che Guix lavora con stringhe base32, da cui la chiamata alla funzione base32.
build-system

È qui che il potere di astrazione fornito dal linguaggio Scheme brilla davvero: in questo caso, il gnu-build-system astrae le famose invocazioni di shell ./configure && make && make install. Altri sistemi di compilazione includono il trivial-build-system che non fa nulla e richiede al manutentore del pacchetto di programmare tutti i passaggi di compilazione, il python-build-system, il emacs-build-system e molti altri (vedi Sistemi di build in Manuale di riferimento di GNU Guix).

synopsis

Dovrebbe essere un riassunto conciso di ciò che fa il pacchetto. Per molti pacchetti, uno slogan dalla home page del progetto può essere usato come sinossi.

description

Come per la sinossi, va bene riutilizzare la descrizione del progetto dalla homepage. Notare che Guix usa la sintassi Texinfo.

home-page

Usa HTTPS se disponibile.

license

Vedere guix/licenses.scm nel sorgente del progetto per un elenco completo delle licenze disponibili.

È ora di compilare il nostro primo pacchetto! Niente di speciale per ora: ci atterremo a un fittizio my-hello, una copia della dichiarazione precedente.

Come per il rituale "Hello World" insegnato con la maggior parte dei linguaggi di programmazione, questo sarà probabilmente l’approccio più "manuale". Elaboreremo una configurazione ideale più tardi; per ora seguiremo la strada più semplice.

Salva quanto segue in un file my-hello.scm.

(use-modules (guix packages)
 (guix download)
 (guix build-system gnu)
 (guix licenses))
(package
 (name "my-hello")
 (version "2.10")
 (source (origin
 (method url-fetch )
 (uri (string-append "mirror://gnu/hello/hello-" version
 ".tar.gz"))
 (sha256
 (base32
 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
 (build-system gnu-build-system )
 (synopsis "Ciao, mondo Guix: Un esempio di pacchetto Guix personalizzato")
 (description
 "GNU Hello stampa il messaggio \"Ciao, mondo!\" e poi esce. Serve
come esempio delle pratiche di codifica standard di GNU. Come tale, supporta
argomenti da riga di comando, più linguaggi, e così via.")
 (home-page "https://www.gnu.org/software/hello/")
 (license gpl3+))

Spiegheremo il codice extra tra un momento.

Sentiti libero di giocare con i diversi valori dei vari campi. Se cambi la sorgente, dovrai aggiornare il checksum. Infatti, Guix si rifiuta di compilare qualsiasi cosa se il checksum fornito non corrisponde al checksum calcolato del codice sorgente. Per ottenere il checksum corretto della dichiarazione del pacchetto, dobbiamo scaricare la sorgente, calcolare il checksum sha256 e convertirlo in base32.

Fortunatamente, Guix può automatizzare questo compito per noi; tutto ciò di cui abbiamo bisogno è fornire l’URI:

$ guix download mirror://gnu/hello/hello-2.10.tar.gz
Inizio download di /tmp/guix-file.JLYgL7
Da https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz...
redirezione a `https://mirror.ibcp.fr/pub/gnu/hello/hello-2.10.tar.gz'...
 ...10.tar.gz 709KiB 2.5MiB/s 00:00 [##################] 100.0%
/gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz
0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i

In questo caso specifico l’output ci dice quale mirror è stato scelto. Se il risultato del comando precedente non è lo stesso dello snippet sopra, aggiorna di conseguenza la tua dichiarazione my-hello.

Nota che i tarball dei pacchetti GNU sono dotati di una firma OpenPGP, quindi dovresti assolutamente controllare la firma di questo tarball con ‘gpg‘ per autenticarlo prima di procedere:

$ guix download mirror://gnu/hello/hello-2.10.tar.gz.sig
Inizio download di /tmp/guix-file.03tFfb
Da https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz.sig...
redirezione a `https://ftp.igh.cnrs.fr/pub/gnu/hello/hello-2.10.tar.gz.sig'. ..
 ....tar.gz.sig 819B 1.2MiB/s 00:00 [##################] 100.0%
/gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig
0q0v86n3y38z17rl146gdakw9xc4mcscpk8dscs412j22glrv9jf
$ gpg --verify /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz
gpg: Firma creata dom 16 nov 2014 13:08:37 CET
gpg: usando la chiave RSA A9553245FDE9B739
gpg: Buona firma da "Sami Kerola <kerolasa@iki.fi>" [sconosciuto]
gpg: alias "Sami Kerola (http://www.iki.fi/kerolasa/) <kerolasa@iki.fi>" [sconosciuto]
gpg: ATTENZIONE: Questa chiave non è certificata con una firma fidata!
gpg: Non c'è alcuna indicazione che la firma appartenga al proprietario.
Impronta della chiave primaria: 8ED3 96E3 7E38 D471 A005 30D3 A955 3245 FDE9 B739

Puoi quindi eseguire felicemente

$ guix package --install-from-file=my-hello.scm

Ora dovresti avere my-hello nel tuo profilo!

$ guix package --list-installed=my-hello
my-hello	2.10	out
/gnu/store/f1db2mfm8syb8qvc357c53slbvf1g9m9-my-hello-2.10

Siamo andati il più lontano possibile senza alcuna conoscenza di Scheme. Prima di passare a pacchetti più complessi, ora è il momento giusto per rispolverare la tua conoscenza di Scheme. Vedi Un corso intensivo di Scheme per mettersi al passo.


2.1.2 Configurazione

Nel resto di questo capitolo faremo affidamento su alcune conoscenze di base di programmazione in Scheme. Ora analizziamo le diverse possibili configurazioni per lavorare sui pacchetti Guix.

Ci sono diversi modi per configurare un ambiente di pacchettizzazione Guix.

Ti consigliamo di lavorare direttamente sul checkout del sorgente di Guix poiché rende più facile per tutti contribuire al progetto.

Ma prima, diamo un’occhiata ad altre possibilità.


Successivo: , Su: Configurazione [Contenuti][Indice]

2.1.2.1 File locale

Questo è quello che abbiamo fatto in precedenza con ‘my-hello’. Con le basi di Scheme che abbiamo trattato, siamo ora in grado di spiegare i blocchi iniziali. Come indicato in guix package --help:

 -f, --install-from-file=FILE
 installa il pacchetto a cui il codice all'interno di FILE
 valuta

Quindi l’ultima espressione must restituire un pacchetto, che è il caso del nostro esempio precedente.

L’espressione use-modules indica quali moduli ci servono nel file. I moduli sono una raccolta di valori e procedure. Sono comunemente chiamati "librerie" o "pacchetti" in altri linguaggi di programmazione.


2.1.2.2 Canali

Guix e la sua collezione di pacchetti possono essere estesi tramite canali. Un canale è un repository Git, pubblico o meno, contenente file .scm che forniscono pacchetti (vedi Definire i pacchetti in Manuale di riferimento di GNU Guix) o servizi (vedi Definire i servizi in Manuale di riferimento di GNU Guix).

Come si crea un canale? Innanzitutto, crea una directory che conterrà i tuoi file .scm, diciamo ~/my-channel:

mkdir ~/my-channel

Supponiamo che tu voglia aggiungere il pacchetto ‘my-hello’ che abbiamo visto in precedenza; prima ha bisogno di alcune modifiche:

(define-module (my-hello)
 #:use-module (guix licenses)
 #:use-module (guix packages)
 #:use-module (guix build-system gnu)
 #:use-module (guix download))
(define-public my-hello
 (package
 (name "my-hello")
 (version "2.10")
 (source (origin
 (method url-fetch )
 (uri (string-append "mirror://gnu/hello/hello-" version
 ".tar.gz"))
 (sha256
 (base32
 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
 (build-system gnu-build-system )
 (synopsis "Ciao, mondo Guix: Un esempio di pacchetto Guix personalizzato")
 (description
 "GNU Hello stampa il messaggio \"Ciao, mondo!\" e poi esce. Serve come esempio delle pratiche di codifica standard di GNU. Come tale, supporta
argomenti da riga di comando, più linguaggi, e così via.")
 (home-page "https://www.gnu.org/software/hello/")
 (license gpl3+)))

Nota che abbiamo assegnato il valore del pacchetto a un nome di variabile esportato con define-public. Questo assegna effettivamente il pacchetto alla variabile my-hello in modo che possa essere referenziato, tra l’altro come dipendenza di altri pacchetti.

Se usi guix package --install-from-file=my-hello.scm sul file precedente, fallirà perché l’ultima espressione, define-public, non restituisce un pacchetto. Se vuoi comunque usare define-public in questo caso, assicurati che il file termini con una valutazione di my-hello:

;; ...
(define-public my-hello
 ;; ...
 )
my-hello

Quest’ultimo esempio non è molto tipico.

Ora come si rende quel pacchetto visibile ai comandi guix in modo da poter testare i pacchetti? È necessario aggiungere la directory al percorso di ricerca usando l’opzione della riga di comando -L, come in questi esempi:

guix show -L ~/my-channel my-hello
guix build -L ~/my-channel my-hello

Il passo finale è trasformare ~/my-channel in un canale vero e proprio, rendendo la tua collezione di pacchetti disponibile senza problemi via qualsiasi comando guix. Per farlo, devi prima renderlo un repository Git:

cd ~/my-channel
git init
git add my-hello.scm
git commit -m "Primo commit del mio canale."

E questo è tutto, hai un canale! Da qui in poi, puoi aggiungere questo canale alla configurazione dei tuoi canali in ~/.config/guix/channels.scm (vedi Specificare canali aggiuntivi in Manuale di riferimento di GNU Guix); supponendo che per ora tu mantenga il tuo canale locale, il file channels.scm assomiglierebbe a qualcosa del genere:

(append (list (channel
 (name 'my-channel)
 (url (string-append "file://" (getenv "HOME")
 "/my-channel"))))
 %default-channels)

La prossima volta che eseguirai guix pull, il tuo canale verrà rilevato e i pacchetti che definisce saranno prontamente disponibili per tutti i comandi guix, anche se non passerai -L. Il comando guix describe mostrerà che Guix sta, effettivamente, usando sia i canali my-channel che guix.

Vedi Creare un canale in Manuale di riferimento di GNU Guix, per i dettagli.


Precedente: , Su: Configurazione [Contenuti][Indice]

2.1.2.3 Modifica diretta dal checkout

Lavorare direttamente sul progetto Guix è consigliato: riduce l’attrito quando arriva il momento di inviare le tue modifiche upstream per far sì che la comunità benefici del tuo duro lavoro!

A differenza della maggior parte delle distribuzioni software, il repository di Guix contiene in un unico posto sia gli strumenti (incluso il gestore di pacchetti) che le definizioni dei pacchetti. Questa scelta è stata fatta per dare agli sviluppatori la flessibilità di modificare l’API senza rotture, aggiornando tutti i pacchetti contemporaneamente. Ciò riduce l’inerzia dello sviluppo.

Dai un’occhiata al repository Git ufficiale:

$ git clone https://git.guix.gnu.org/guix.git

Nel resto di questo articolo, useremo ‘$GUIX_CHECKOUT’ per fare riferimento alla posizione del checkout.

Segui le istruzioni nel manuale (vedi Contribuire in Manuale di riferimento di GNU Guix) per configurare l’ambiente del repository.

Una volta pronto, dovresti essere in grado di utilizzare le definizioni dei pacchetti dall’ambiente del repository.

Sentiti libero di modificare le definizioni dei pacchetti che si trovano in ‘$GUIX_CHECKOUT/gnu/packages’.

Lo script ‘$GUIX_CHECKOUT/pre-inst-env’ ti consente di usare ‘guix’ sulla collezione di pacchetti del repository (vedi Eseguire Guix prima di installarlo in Manuale di riferimento di GNU Guix).

  • Cerca pacchetti, come Ruby:
     $ cd $GUIX_CHECKOUT
     $ ./pre-inst-env guix package --list-available=ruby
     ruby 1.8.7-p374 out gnu/packages/ruby.scm:119:2
     ruby 2.1.6 out gnu/packages/ruby.scm:91:2
     ruby 2.2.2 out gnu/packages/ruby.scm:39:2
    
  • Compila un pacchetto, qui Ruby versione 2.1:
     $ ./pre-inst-env guix build --keep-failed ruby@2.1
     /gnu/store/c13v73jxmj2nir2xjqaz5259zywsa9zi-ruby-2.1.6
    
  • Installalo nel tuo profilo utente:
     $ ./pre-inst-env guix package --install ruby@2.1
    
  • Controlla errori comuni:
     $ ./pre-inst-env guix lint ruby@2.1
    

Guix si impegna a mantenere uno standard di pacchettizzazione elevato; quando contribuisci al progetto Guix, ricorda di

  • seguire lo stile di codifica (vedi Stile del codice in Manuale di riferimento di GNU Guix),
  • e rivedere la lista di controllo dal manuale (vedi Invia delle patches in Manuale di riferimento di GNU Guix).

Una volta che sei soddisfatto del risultato, sei il benvenuto a inviare il tuo contributo per renderlo parte di Guix. Questo processo è anche dettagliato nel manuale. (vedi Contribuire in Manuale di riferimento di GNU Guix)

È uno sforzo della comunità, quindi più persone si uniscono, migliore diventa Guix!


2.1.3 Esempio esteso

L’esempio "Ciao Mondo" sopra è il più semplice possibile. I pacchetti possono essere più complessi di così e Guix può gestire scenari più avanzati. Diamo un’occhiata a un altro pacchetto più sofisticato (leggermente modificato dalla fonte):

(define-module (gnu packages version-control)
 #:use-module ((guix licenses) #:prefix license:)
 #:use-module (guix utils)
 #:use-module (guix packages)
 #:use-module (guix git-download)
 #:use-module (guix build-system cmake)
 #:use-module (gnu packages)
 #:use-module (gnu packages compression)
 #:use-module (gnu packages pkg-config)
 #:use-module (gnu packages python)
 #:use-module (gnu packages ssh)
 #:use-module (gnu packages tls)
 #:use-module (gnu packages web))
(define-public my-libgit2
 (let ((commit "e98d0a37c93574d2c6107bf7f31140b548c6a7bf")
 (revision "1"))
 (package
 (name "my-libgit2")
 (version (git-version "0.26.6" revision commit))
 (source (origin
 (method git-fetch )
 (uri (git-reference
 (url "https://github.com/libgit2/libgit2/")
 (commit commit)))
 (file-name (git-file-name name version ))
 (sha256
 (base32
 "17pjvprmdrx4h6bb1hhc98w9qi6ki7yl57f090n9kbhswxqfs7s3"))
 (patches (search-patches "libgit2-mtime-0.patch"))
 (modules '((guix build utils)))
 ;; Rimuovi software in bundle.
 (snippet '(delete-file-recursively "deps"))))
 (build-system cmake-build-system )
 (outputs '("out" "debug"))
 (arguments
 `(#:tests? #true ; Esegui la suite di test (questo è il valore predefinito)
 #:configure-flags '("-DUSE_SHA1DC=ON") ; Rilevamento collisioni SHA-1
 #:phases
 (modify-phases %standard-phases
 (add-after 'unpack 'fix-hardcoded-paths
 (lambda _
 (substitute* "tests/repo/init.c"
 (("#!/bin/sh") (string-append "#!" (which "sh"))))
 (substitute* "tests/clar/fs.h"
 (("/bin/cp") (which "cp"))
 (("/bin/rm") (which "rm")))))
 ;; Esegui i controlli in modo più verboso.
 (replace 'check
 (lambda* (#:key tests? #:allow-other-keys)
 (when tests?
 (invoke "./libgit2_clar" "-v" "-Q"))))
 (add-after 'unpack 'make-files-writable-for-tests
 (lambda _ (for-each make-file-writable (find-files ".")))))))
 (inputs
 (list libssh2 http-parser python-wrapper))
 (native-inputs
 (list pkg-config))
 (propagated-inputs
 ;; Queste due librerie sono in 'Requires.private' in libgit2.pc.
 (list openssl zlib))
 (home-page "https://libgit2.github.com/")
 (synopsis "Libreria che fornisce i metodi core di Git")
 (description
 "Libgit2 è un'implementazione portatile e pura in C dei metodi core di Git
fornita come libreria rientrante collegabile con una solida API, che consente di
scrivere applicazioni Git personalizzate a velocità nativa in qualsiasi linguaggio con binding.")
 ;; GPLv2 con eccezione di linking
 (license license:gpl2))))

(Nei casi in cui si desidera solo modificare alcuni campi da una definizione di pacchetto, si dovrebbe fare affidamento sull’ereditarietà invece di copiare e incollare tutto. Vedi sotto.)

Discutiamo questi campi in dettaglio.

2.1.3.1 Metodo git-fetch

A differenza del metodo url-fetch, git-fetch si aspetta un git-reference che accetta un repository Git e un commit. Il commit può essere qualsiasi riferimento Git come i tag, quindi se la version è taggata, allora può essere usata direttamente. A volte il tag è preceduto da una v, nel qual caso si userebbe (commit (string-append "v" version)).

Per assicurarsi che il codice sorgente dal repository Git sia memorizzato in una directory con un nome descrittivo, usiamo (file-name (git-file-name name version)).

La procedura git-version può essere usata per derivare la versione quando si impacchettano programmi per un commit specifico, seguendo le linee guida per i contributori di Guix (vedi Numeri di versione in Manuale di riferimento di GNU Guix).

Come si ottiene l’hash sha256 che si trova lì, chiedi? Invocando guix hash su un checkout del commit desiderato, in questo modo:

git clone https://github.com/libgit2/libgit2/
cd libgit2
git checkout v0.26.6
guix hash -rx .

guix hash -rx calcola un hash SHA256 sull’intera directory, escludendo la sottodirectory .git (vedi Invocare guix hash in Manuale di riferimento di GNU Guix).

In futuro, guix download sarà, si spera, in grado di eseguire questi passaggi per te, proprio come fa per i download normali.

2.1.3.2 Frammenti

Gli snippet sono codice Scheme quotato (cioè non valutato) che è un mezzo per applicare patch al sorgente. Sono un’alternativa in stile Guix ai tradizionali file .patch. A causa della quotatura, il codice viene valutato solo quando passato al demone Guix per la costruzione. Possono esserci quanti snippet sono necessari.

Gli snippet potrebbero aver bisogno di moduli Guile aggiuntivi che possono essere importati dal campo modules.

2.1.3.3 Input

Ci sono 3 diversi tipi di input. In breve:

native-inputs

Richiesti per la compilazione ma non per il runtime – l’installazione di un pacchetto tramite un sostituto non installerà questi input.

inputs

Installati nello store ma non nel profilo, oltre ad essere presenti al momento della compilazione.

propagated-inputs

Installati nello store e nel profilo, oltre ad essere presenti al momento della compilazione.

Vedi Riferimenti per 'package' in Manuale di riferimento di GNU Guix per maggiori dettagli.

La distinzione tra i vari input è importante: se una dipendenza può essere gestita come un input invece di un input propagato, dovrebbe essere fatto così, altrimenti “inquina” il profilo utente senza una buona ragione.

Ad esempio, un utente che installa un programma grafico che dipende da uno strumento a riga di comando potrebbe essere interessato solo alla parte grafica, quindi non è necessario forzare lo strumento a riga di comando nel profilo utente. La dipendenza è una preoccupazione del pacchetto, non dell’utente. Gli Inputs rendono possibile gestire le dipendenze senza infastidire l’utente aggiungendo file eseguibili (o librerie) indesiderati al loro profilo.

Lo stesso vale per gli native-inputs: una volta installato il programma, le dipendenze di compilazione possono essere tranquillamente raccolte come spazzatura. È importante anche quando è disponibile un sostituto, nel qual caso verranno scaricati solo gli inputs e gli propagated inputs: gli native inputs non sono richiesti per installare un pacchetto da un sostituto.

Nota: Potresti vedere qua e là snippet in cui gli input dei pacchetti sono scritti in modo piuttosto diverso, come questo:

;; Il "vecchio stile" per gli input.
(inputs
 `(("libssh2" ,libssh2)
 ("http-parser" ,http-parser)
 ("python" ,python-wrapper)))

Questo è il “vecchio stile”, dove a ciascun input nell’elenco viene esplicitamente data un’etichetta (una stringa). È ancora supportato ma raccomandiamo di usare invece lo stile sopra. Vedi Riferimenti per 'package' in Manuale di riferimento di GNU Guix, per maggiori informazioni.

2.1.3.4 Prodotti

Proprio come un pacchetto può avere più input, può anche produrre più output.

Ogni output corrisponde a una directory separata nello store.

L’utente può scegliere quale output installare; questo è utile per risparmiare spazio o per evitare di inquinare il profilo utente con eseguibili o librerie indesiderate.

La separazione dell’output è opzionale. Quando il campo outputs viene omesso, l’output predefinito e unico (il pacchetto completo) è indicato come "out".

I nomi tipici degli output separati includono debug e doc.

Si consiglia di separare gli output solo quando si è dimostrato che ne vale la pena: se la dimensione dell’output è significativa (confrontare con guix size) o nel caso in cui il pacchetto sia modulare.

2.1.3.5 Argomenti del sistema di compilazione

L’argomento arguments è un elenco di coppie chiave-valore utilizzato per configurare il processo di compilazione.

L’argomento più semplice #:tests? può essere utilizzato per disabilitare la suite di test durante la compilazione del pacchetto. Questo è utile soprattutto quando il pacchetto non dispone di alcuna suite di test. Si consiglia vivamente di mantenere la suite di test attiva se presente.

Un altro argomento comune è :make-flags, che specifica un elenco di flag da aggiungere quando si esegue make, come si farebbe dalla riga di comando. Ad esempio, i seguenti flag

#:make-flags (list (string-append "prefix=" (assoc-ref %outputs "out"))
 "CC=gcc")

si traducono in

$ make CC=gcc prefix=/gnu/store/...-<out>

Questo imposta il compilatore C a gcc e la variabile prefix (la directory di installazione nel linguaggio Make) a (assoc-ref %outputs "out"), che è una variabile globale di fase di compilazione che punta alla directory di destinazione nello store (qualcosa come /gnu/store/...-my-libgit2-20180408).

Allo stesso modo, è possibile impostare i flag di configurazione:

#:configure-flags '("-DUSE_SHA1DC=ON")

La variabile %build-inputs viene anche generata nello scope. È una tabella di associazione che mappa i nomi degli input alle loro directory dello store.

La parola chiave phases elenca i passaggi sequenziali del sistema di compilazione. Tipicamente le fasi includono unpack, configure, build, install e check. Per saperne di più su queste fasi, è necessario trovare la definizione appropriata del sistema di compilazione in ‘$GUIX_CHECKOUT/ guix/build/gnu-build-system.scm’:

(define %standard-phases
 ;; Fasi di compilazione standard, come un elenco di coppie simbolo/procedura.
 (let-syntax ((phases (syntax-rules ()
 ((_ p ... ) `((p . ,p) ... )))))
 (phases set-SOURCE-DATE-EPOCH set-paths install-locale unpack
 bootstrap
 patch-usr-bin-file
 patch-source-shebangs configure patch-generated-file-shebangs
 build check install
 patch-shebangs strip
 validate-runpath
 validate-documentation-location
 delete-info-dir-file
 patch-dot-desktop-files
 make-dynamic-linker-cache
 install-license-files
 reset-gzip-timestamps
 compress-documentation)))

O dalla REPL:

(add-to-load-path "/path/to/guix/checkout")
,use (guix build gnu-build-system )
(map car %standard-phases)
 (set-SOURCE-DATE-EPOCH set-paths install-locale unpack bootstrap patch-usr-bin-file patch-source-shebangs configure patch-generated-file-shebangs build check install patch-shebangs strip validate-runpath validate-documentation-location delete-info-dir-file patch-dot-desktop-files make-dynamic-linker-cache install-license-files reset-gzip-timestamps compress-documentation)

Se vuoi saperne di più su cosa succede durante queste fasi, consulta le procedure associate.

Ad esempio, al momento in cui scrivo, la definizione di unpack per il sistema di compilazione GNU è:

(define* (unpack #:key source #:allow-other-keys)
 "Decomprime SOURCE nella directory di lavoro e cambia directory all'interno del
sorgente. Quando SOURCE è una directory, copiala in una sottodirectory della
directory di lavoro corrente."
 (if (file-is-directory? source)
 (begin
 (mkdir "source")
 (chdir "source")
 ;; Preserva i timestamp (impostati sull'Epoch) sull'albero copiato in modo che
 ;; le cose funzionino in modo deterministico.
 (copy-recursively source "."
 #:keep-mtime? #t)
 ;; Rendi scrivibili i file del checkout sorgente, per comodità.
 (for-each (lambda (f)
 (false-if-exception (make-file-writable f)))
 (find-files ".")))
 (begin
 (cond
 ((string-suffix? ".zip" source)
 (invoke "unzip" source))
 ((tarball? source)
 (invoke "tar" "xvf" source))
 (else
 (let ((name (strip-store-file-name source))
 (command (compressor source)))
 (copy-file source name)
 (when command
 (invoke command "--decompress" name)))))
 ;; Tenta di cambiare nella directory figlia.
 (and=> (first-subdirectory ".") chdir ))))

Nota la chiamata chdir: cambia la directory di lavoro dove il sorgente è stato decompresso. Quindi ogni fase successiva a unpack userà il sorgente come directory di lavoro, ecco perché possiamo lavorare direttamente sui file sorgente. Cioè, a meno che una fase successiva non cambi la directory di lavoro in qualcos’altro.

Modifichiamo l’elenco di %standard-phases del sistema di compilazione con la macro modify-phases secondo l’elenco delle modifiche specificate, che possono avere le seguenti forme:

  • (add-before phase new-phase procedure): Esegue la procedure denominata new-phase prima di phase.
  • (add-after phase new-phase procedure): Idem, ma dopo.
  • (replace phase procedure).
  • (delete phase).

La procedure supporta gli argomenti con parola chiave inputs e outputs. Ogni input (sia native, propagato o meno) e la directory di output sono referenziati dai loro nomi in quelle variabili. Quindi (assoc-ref outputs "out") è la directory dello store dell’output principale del pacchetto. Una procedura di fase può apparire così:

(lambda* (#:key inputs outputs #:allow-other-keys)
 (let ((bash-directory (assoc-ref inputs "bash"))
 (output-directory (assoc-ref outputs "out"))
 (doc-directory (assoc-ref outputs "doc")))
 ;; ... ))

Il suo valore di ritorno viene ignorato.

2.1.3.6 Code staging

Il lettore attento potrebbe aver notato la sintassi di quasi-citazione e virgola nel campo argomento. Infatti, il codice di compilazione nella dichiarazione del pacchetto non dovrebbe essere valutato lato client, ma solo quando passato al demone Guix. Questo meccanismo di passaggio di codice tra due processi in esecuzione è chiamato staging del codice.

2.1.3.7 Funzioni di utilità

Quando si personalizzano le phases, spesso è necessario scrivere codice che imita le invocazioni di sistema equivalenti (make, mkdir, cp, ecc.) comunemente usate durante le normali installazioni in “stile Unix”.

Alcune come chmod sono native di Guile. Vedi Manuale di riferimento di Guile per un elenco completo.

Guix fornisce funzioni helper aggiuntive che si rivelano particolarmente utili nel contesto della gestione dei pacchetti.

Alcune di queste funzioni si trovano in ‘$GUIX_CHECKOUT/guix/guix/build/ utils.scm’. La maggior parte di esse riflette il comportamento dei comandi di sistema Unix tradizionali:

which

Come il comando di sistema ‘which’.

find-files

Simile al comando di sistema ‘find’.

mkdir-p

Come ‘mkdir -p’, che crea tutti i genitori se necessario.

install-file

Simile a ‘install’ quando si installa un file in una directory (possibilmente non esistente). Guile ha copy-file che funziona come ‘cp’.

copy-recursively

Come ‘cp -r’.

delete-file-recursively

Come ‘rm -rf’.

invoke

Esegui un eseguibile. Questo dovrebbe essere usato al posto di system*.

with-directory-excursion

Esegui il corpo in una diversa directory di lavoro, quindi ripristina la precedente directory di lavoro.

substitute*

Una funzione “simile a sed”.

Vedi Utilità di build in Manuale di riferimento di GNU Guix, per maggiori informazioni su queste utilità.

2.1.3.8 Prefisso modulo

La licenza nel nostro ultimo esempio richiede un prefisso: ciò è dovuto a come il modulo license è stato importato nel pacchetto, come #:use-module ((guix licenses) #:prefix license:). Il meccanismo di importazione dei moduli Guile (vedi Using Guile Modules in Manuale di riferimento di Guile) offre all’utente il controllo completo sulla gestione degli spazi dei nomi: ciò è necessario per evitare conflitti tra, ad esempio, la variabile ‘zlib’ di ‘licenses.scm’ (un valore di license) e la variabile ‘zlib’ di ‘compression.scm’ (un valore di package).


2.1.4 Altri sistemi di build

Quanto abbiamo visto finora copre la maggior parte dei pacchetti che utilizzano un sistema di compilazione diverso da trivial-build-system. Quest’ultimo non automatizza nulla e ti lascia il compito di compilare tutto manualmente. Questo può essere più impegnativo e per ora non lo tratteremo qui, ma fortunatamente è raramente necessario ricorrere a questo sistema.

Per gli altri sistemi di compilazione, come ASDF, Emacs, Perl, Ruby e molti altri, il processo è molto simile al sistema di compilazione GNU, ad eccezione di alcuni argomenti specializzati.

Vedi Sistemi di build in Manuale di riferimento di GNU Guix, per maggiori informazioni sui sistemi di compilazione, o controlla il codice sorgente nelle directory ‘$GUIX_CHECKOUT/guix/build’ e ‘$GUIX_CHECKOUT/guix/build-system’.


2.1.5 Definizione di pacchetto programmabile e automatizzata

Non possiamo ripeterlo abbastanza: avere un linguaggio di programmazione completo a portata di mano ci dà potere in modi che vanno ben oltre la tradizionale gestione dei pacchetti.

Illustriamo questo con alcune fantastiche funzionalità di Guix!


2.1.5.1 Importatori ricorsivi

Potresti trovare alcuni sistemi di compilazione così buoni che c’è poco da fare per scrivere un pacchetto, al punto che diventa ripetitivo e noioso dopo un po’. Una ragione d’essere dei computer è quella di sostituire gli esseri umani in questi compiti noiosi. Quindi, diciamo a Guix di farlo per noi e di creare la definizione di pacchetto di un pacchetto R da CRAN (l’output è troncato per brevità):

$ guix import cran --recursive walrus
(define-public r-mc2d
 ; ...
 (license gpl2+)))
(define-public r-jmvcore
 ; ...
 (license gpl2+)))
(define-public r-wrs2
 ; ...
 (license gpl3)))
(define-public r-walrus
 (package
 (name "r-walrus")
 (version "1.0.3")
 (source
 (origin
 (method url-fetch)
 (uri (cran-uri "walrus" version))
 (sha256
 (base32
 "1nk2glcvy4hyksl5ipq2mz8jy4fss90hx6cq98m3w96kzjni6jjj"))))
 (build-system r-build-system)
 (propagated-inputs
 (list r-ggplot2 r-jmvcore r-r6 r-wrs2))
 (home-page "https://github.com/jamovi/walrus")
 (synopsis "Metodi Statistici Robusti")
 (description
 "Questo pacchetto fornisce una cassetta degli attrezzi di comuni test statistici robusti,
inclusi descrittori robusti, t-test robusti e ANOVA robusta.
È disponibile anche come modulo per 'jamovi' (vedere
<https://www.jamovi.org> per maggiori informazioni). Walrus si basa sul
pacchetto WRS2 di Patrick Mair, che a sua volta si basa sugli script e sul
lavoro di Rand Wilcox. Queste analisi sono descritte in dettaglio nel libro
'Introduction to Robust Estimation & Hypothesis Testing'.")
 (license gpl3)))

L’importatore ricorsivo non importerà i pacchetti per i quali Guix ha già definizioni di pacchetto, ad eccezione del primissimo.

Non tutte le applicazioni possono essere impacchettate in questo modo, solo quelle che si basano su un numero selezionato di sistemi supportati. Leggi l’elenco completo degli importatori nella sezione import di guix del manuale (vedi Invocare guix import in Manuale di riferimento di GNU Guix).


2.1.5.2 Aggiornamento automatico

Guix è abbastanza intelligente da controllare gli aggiornamenti sui sistemi che conosce. Può segnalare definizioni di pacchetto obsolete con

$ guix refresh hello

Nella maggior parte dei casi, l’aggiornamento di un pacchetto a una versione più recente richiede poco più che la modifica del numero di versione e del checksum. Guix può farlo anche automaticamente:

$ guix refresh hello --update

2.1.5.3 Ereditarietà

Se hai iniziato a sfogliare le definizioni dei pacchetti esistenti, potresti aver notato che un numero significativo di esse ha un campo inherit:

(define-public adwaita-icon-theme
 (package (inherit gnome-icon-theme)
 (name "adwaita-icon-theme")
 (version "3.26.1")
 (source (origin
 (method url-fetch )
 (uri (string-append "mirror://gnome/sources/" name "/"
 (version-major+minor version ) "/"
 name "-" version ".tar.xz"))
 (sha256
 (base32
 "17fpahgh5dyckgz7rwqvzgnhx53cx9kr2xw0szprc6bnqy977fi8"))))
 (native-inputs (list `(,gtk+ "bin")))))

Tutti i campi non specificati sono ereditati dal pacchetto padre. Questo è molto comodo per creare pacchetti alternativi, ad esempio con sorgenti, versioni o opzioni di compilazione diverse.


2.1.6 Ottenere aiuto

Purtroppo, alcune applicazioni possono essere difficili da impacchettare. A volte hanno bisogno di una patch per funzionare con la gerarchia del file system non standard imposta dallo store. A volte i test non vengono eseguiti correttamente. (Possono essere saltati ma questo non è raccomandato.) Altre volte il pacchetto risultante non sarà riproducibile.

Se dovessi trovarti bloccato, incapace di capire come risolvere qualsiasi tipo di problema di packaging, non esitare a chiedere aiuto alla comunità.

Vedi la homepage di Guix per informazioni sulle mailing list, IRC, ecc.


2.1.7 Conclusione

Questo tutorial è stato una vetrina della sofisticata gestione dei pacchetti di cui Guix si vanta. A questo punto abbiamo in gran parte limitato questa introduzione al gnu-build-system che è un livello di astrazione fondamentale su cui si basano astrazioni più avanzate.

Da dove proseguiamo? Successivamente dovremmo dissezionare le viscere del sistema di compilazione rimuovendo tutte le astrazioni, usando il trivial-build-system: questo dovrebbe darci una comprensione approfondita del processo prima di indagare su alcune tecniche di packaging più avanzate e casi limite.

Altre funzionalità degne di esplorazione sono le capacità di editing e debugging interattivi di Guix fornite dal Guile REPL.

Queste fantasiose funzionalità sono completamente opzionali e possono aspettare; ora è un buon momento per prendersi una meritata pausa. Con quanto abbiamo introdotto qui dovresti essere ben attrezzato per impacchettare molti programmi. Puoi iniziare subito e speriamo di vedere i tuoi contributi presto!


Precedente: , Su: Impacchettamento [Contenuti][Indice]

2.2 Packaging Workflows

The following sections provide real-life examples on working with specific build systems, serving as extensions to the concise packaging guidelines (vedi Packaging Guidelines in GNU Guix Reference Manual).


2.2.1 Packaging Rust Crates

In preparation, add the following packages to our environment:

$ guix shell rust rust:cargo cargo-audit cargo-license

2.2.1.1 Common Workflow for Rust Packaging

In this example, we’ll package cargo-audit, which is published on the crates.io Rust package repository. All its dependencies are on crates.io as well.

  1. Since cargo-audit is available on crates.io, we can generate a template via the crates.io importer (vedi Invoking guix import in GNU Guix Reference Manual):
    $ guix import crate cargo-audit
    

    After manual editing, we’ll have the following definiton:

    (define-public cargo-audit
     (package
     (name "cargo-audit")
     (version "0.21.2")
     (source
     (origin
     (method url-fetch )
     (uri (crate-uri "cargo-audit" version ))
     (file-name (string-append name "-" version ".tar.gz"))
     (sha256
     (base32 "1a00yqpckkw86zh2hg7ra82c5fx0ird5766dyynimbvqiwg2ps0n"))))
     (build-system cargo-build-system )
     (arguments (list #:install-source? #f))
     (inputs (cargo-inputs 'cargo-audit))
     (home-page "https://rustsec.org/")
     (synopsis "Audit Cargo.lock for crates with security vulnerabilities")
     (description
     "This package provides a Cargo subcommand, @command{cargo audit}, to
    audit @file{Cargo.lock} for crates with security vulnerabilities.")
     (license (list license:asl2.0 license:expat))))
    

    The identifier used to invoke cargo-inputs, in this case 'cargo-audit, must be unique, usually matching the variable name of the package.

  2. Unpack package source and navigate to the unpacked directory, then run the following commands:
    $ cargo generate-lockfile
    $ cargo audit
    $ cargo license
    

    cargo generate-lockfile updates dependencies to compatible versions. Applying it to all Rust applications helps reduce a great number of Rust libraries we need to check later. Although sometimes libraries may fail to follow the semantic versioning scheme, it’s still acceptable.

    cargo audit checks known vulnerabilities and cargo license checks licenses, for all the dependencies. We must have an acceptable output of cargo audit and ensure all dependencies are licensed with our supported licenses (vedi Defining Packages in GNU Guix Reference Manual).

  3. Import dependencies from the generated lockfile:
    $ guix import --insert=gnu/packages/rust-crates.scm \
     crate --lockfile=/path/to/Cargo.lock cargo-audit
    # Or use short options, in this case the shell processes file names
    # before passing them to Guix, allowing tilde expansion, for example.
    $ guix import -i gnu/packages/rust-crates.scm \
     crate -f /path/to/Cargo.lock cargo-audit
    

    cargo-audit here must be consistent with the identifier used for cargo-inputs invocation in the package definition.

    At this stage, the package cargo-audit is buildable.

  4. Finally we’ll unbundle the vendored dependencies. The lockfile importer inserts TODO: comments for libraries with high probability of bundled dependencies. cargo-build-system also performs additional check for binary files in its check-for-pregenerated-files phase, which usually indicates bundling:
    $ ./pre-inst-env guix build cargo-audit
    …
    starting phase `check-for-pregenerated-files'
    Searching for binary files...
    ./guix-vendor/rust-async-compression-0.4.21.tar.gz/tests/artifacts/dictionary-rust
    ./guix-vendor/rust-async-compression-0.4.21.tar.gz/tests/artifacts/dictionary-rust-other
    ./guix-vendor/rust-async-compression-0.4.21.tar.gz/tests/artifacts/lib.rs.zst
    ./guix-vendor/rust-async-compression-0.4.21.tar.gz/tests/artifacts/long-window-size-lib.rs.zst
    ./guix-vendor/rust-winapi-i686-pc-windows-gnu-0.4.0.tar.gz/lib/libwinapi_aclui.a
    ./guix-vendor/rust-winapi-i686-pc-windows-gnu-0.4.0.tar.gz/lib/libwinapi_activeds.a
    ./guix-vendor/rust-winapi-i686-pc-windows-gnu-0.4.0.tar.gz/lib/libwinapi_asycfilt.a
    ./guix-vendor/rust-winapi-i686-pc-windows-gnu-0.4.0.tar.gz/lib/libwinapi_amsi.a
    …
    

    Although Rust libraries are not publicly exported, we can still select them via the Guix command-line interface via a Guile expression:

    $ guix build --expression='(@@ (gnu packages rust-crates) rust-ring-0.17.14)'
    

    To unbundle most dependencies, a snippet is sufficient:

    (define rust-curl-sys-0.4.80+curl-8.12.1
     (crate-source "curl-sys" "0.4.80+curl-8.12.1"
     "0d7ppx4kq77hc5nyff6jydmfabpgd0i3ppjvn8x0q833mhpdzxsm"
     #:snippet '(delete-file-recursively "curl")))
    
    (define rust-bzip2-sys-0.1.13+1.0.8
     (crate-source "bzip2-sys" "0.1.13+1.0.8"
     "056c39pgjh4272bdslv445f5ry64xvb0f7nph3z7860ln8rzynr2"
     #:snippet
     '(begin
     (delete-file-recursively "bzip2-1.0.8")
     (delete-file "build.rs")
     (with-output-to-file "build.rs"
     (lambda _
     (format #t "fn main() {~@
     println!(\"cargo:rustc-link-lib=bz2\");~@
     }~%"))))))
    

    In a more complex case, where unbundling one dependency requires a build process that involves other packages, we should make a full package in (gnu packages rust-sources) first and reference it in the imported definition.

    For example, we have defined a rust-ring-0.17 in (gnu packages rust-sources), then the imported definition in (gnu packages rust-crates) should be modified to reference it.

    (define rust-ring-0.17.14 rust-ring-0.17)
    

    When one dependency can be safely removed, modify it to #f.

    (define rust-openssl-src-300.4.2+3.4.1 #f)
    

    To facilitate various tasks in the common workflow, several scripts are provided in the etc/teams/rust directory of Guix source tree.


2.2.1.2 Cargo Workspaces and Development Snapshots

In this example, we’ll package niri, which depends on development snapshots (also Cargo workspaces here).

As we can’t ensure compatibility of a development snapshot, before executing cargo generate-lockfile, we should modify Cargo.toml to pin it to a known working revision.

To use our packaged development snapshots, it’s also necessary to modify Cargo.toml in a build phase, with a package-specific substitution pattern.

(define-public niri
 (package
 (name "niri")
 (version "25.02")
 (source (origin
 (method git-fetch )
 (uri (git-reference
 (url "https://github.com/YaLTeR/niri")
 (commit (string-append "v" version ))))
 (file-name (git-file-name name version ))
 (sha256
 (base32
 "0vzskaalcz6pcml687n54adjddzgf5r07gggc4fhfsa08h1wfd4r"))))
 (build-system cargo-build-system )
 (arguments
 (list #:install-source? #f
 #:phases
 #~(modify-phases %standard-phases
 (add-after 'unpack 'use-guix-vendored-dependencies
 (lambda _
 (substitute* "Cargo.toml"
 (("# version =.*")
 "version = \"*\"")
 (("git.*optional")
 "version = \"*\", optional")
 (("^git = .*")
 "")))))))
 (native-inputs
 (list pkg-config))
 (inputs
 (cons* clang
 libdisplay-info
 libinput-minimal
 libseat
 libxkbcommon
 mesa
 pango
 pipewire
 wayland
 (cargo-inputs 'niri)))
 (home-page "https://github.com/YaLTeR/niri")
 (synopsis "Scrollable-tiling Wayland compositor")
 (description
 "Niri is a scrollable-tiling Wayland compositor which arranges windows in a
scrollable format. It is considered stable for daily use and performs most
functions expected of a Wayland compositor.")
 (license license:gpl3+)))

niri has Cargo workspace dependencies. When packaging a Cargo workspace dependency, parameter #:cargo-package-crates is required.

(define-public rust-pipewire-0.8.0.fd3d8f7
 (let ((commit "fd3d8f7861a29c2eeaa4c393402e013578bb36d9")
 (revision "0"))
 (package
 (name "rust-pipewire")
 (version (git-version "0.8.0" revision commit))
 (source
 (origin
 (method git-fetch )
 (uri (git-reference
 (url "https://gitlab.freedesktop.org/pipewire/pipewire-rs.git")
 (commit commit)))
 (file-name (git-file-name name version ))
 (sha256
 (base32 "1hzyhz7xg0mz8a5y9j6yil513p1m610q3j9pzf6q55vdh5mcn79v"))))
 (build-system cargo-build-system )
 (arguments
 (list #:skip-build? #t
 #:cargo-package-crates
 ''("libspa-sys" "libspa" "pipewire-sys" "pipewire")))
 (inputs (cargo-inputs 'rust-pipewire-0.8.0.fd3d8f7))
 (home-page "https://pipewire.org/")
 (synopsis "Rust bindings for PipeWire")
 (description "This package provides Rust bindings for PipeWire.")
 (license license:expat))))

Don’t forget to modify all workspace members in (gnu packages rust-crates):

(define rust-pipewire-0.8.0.fd3d8f7 rust-pipewire-0.8.0.fd3d8f7)
(define rust-pipewire-sys-0.8.0.fd3d8f7 rust-pipewire-0.8.0.fd3d8f7)
...
(define rust-libspa-0.8.0.fd3d8f7 rust-pipewire-0.8.0.fd3d8f7)
(define rust-libspa-sys-0.8.0.fd3d8f7 rust-pipewire-0.8.0.fd3d8f7)

2.2.1.3 Using Rust Libraries in Other Build Systems

In this example, we’ll package libchewing, which combines two build systems.

When building Rust packages in other build systems, we need to add rust, and rust:cargo to native-inputs, import and use modules from both build systems, and apply necessary build phases from cargo-build-system.

For cross-compilation support, we’ll also add rust-sysroot created with (make-rust-sysroot (%current-target-system)) to native-inputs, and set #:cargo-target for cargo-build-system’s build phases.

(define-public libchewing
 (package
 (name "libchewing")
 (version "0.9.1")
 (source
 (origin
 (method git-fetch )
 (uri (git-reference
 (url "https://github.com/chewing/libchewing")
 (commit (string-append "v" version ))))
 (file-name (git-file-name name version ))
 (sha256
 (base32 "0gh64wvrk5pn0fhmpvj1j99d5g7f7697rk96zbkc8l72yjr819z5"))))
 (build-system cmake-build-system )
 (arguments
 (list #:imported-modules
 (append %cmake-build-system-modules
 %cargo-build-system-modules)
 #:modules
 '(((guix build cargo-build-system ) #:prefix cargo:)
 (guix build cmake-build-system )
 (guix build utils))
 #:phases
 #~(modify-phases %standard-phases
 (add-after 'unpack 'prepare-cargo-build-system
 (lambda args
 (for-each
 (lambda (phase)
 (format #t "Running cargo phase: ~a~%" phase)
 (apply (assoc-ref cargo:%standard-phases phase)
 ;; For cross-compilation.
 #:cargo-target #$(cargo-triplet)
 args))
 '(unpack-rust-crates
 configure
 check-for-pregenerated-files
 patch-cargo-checksums)))))))
 (native-inputs
 (append
 (list rust `(,rust "cargo") )
 ;; For cross-compilation.
 (or (and=> (%current-target-system)
 (compose list make-rust-sysroot))
 '())))
 (inputs
 (cons* corrosion ncurses sqlite (cargo-inputs 'libchewing)))
 (synopsis "Chinese phonetic input method")
 (description "Chewing is an intelligent phonetic (Zhuyin/Bopomofo) input
method, one of the most popular choices for Traditional Chinese users.")
 (home-page "https://chewing.im/")
 (license license:lgpl2.1+)))

Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

3 Configurazione di sistema

Guix offre un linguaggio flessibile per configurare dichiarativamente il tuo sistema Guix. Questa flessibilità può a volte essere eccessiva. Lo scopo di questo capitolo è dimostrare alcuni concetti avanzati di configurazione.

vedi Configurazione di sistema in Manuale di riferimento di GNU Guix per un riferimento completo.


Successivo: , Su: Configurazione di sistema [Contenuti][Indice]

3.1 Accesso automatico a una TTY specifica

Mentre il manuale di Guix spiega l’auto-login di un utente su tutte le TTY (vedi auto-login to TTY in Manuale di riferimento di GNU Guix), alcuni potrebbero preferire una situazione in cui un utente è loggato su una TTY con le altre TTY configurate per accedere a utenti diversi o a nessuno. Si noti che si può auto-loggare un utente su qualsiasi TTY, ma di solito è consigliabile evitare tty1, che, per impostazione predefinita, viene utilizzata per registrare avvisi ed errori.

Ecco come si potrebbe impostare l’accesso automatico per un utente a una tty:

(define (auto-login-to-tty config tty user)
 (if (string=? tty (mingetty-configuration-tty config))
 (mingetty-configuration
 (inherit config)
 (auto-login user))
 config))
(define %my-services
 (modify-services %base-services
 ;; ...
 (mingetty-service-type config =>
 (auto-login-to-tty
 config "tty3" "alice"))))
(operating-system
 ;; ...
 (services %my-services))

Si potrebbe anche compose (vedi Higher-Order Functions in Manuale di riferimento di Guile) auto-login-to-tty per accedere a più utenti su più tty.

Infine, ecco una nota di cautela. Impostare l’auto-login su una TTY significa che chiunque può accendere il tuo computer ed eseguire comandi come il tuo utente regolare. Tuttavia, se hai una partizione root crittografata, e quindi hai già bisogno di inserire una passphrase all’avvio del sistema, l’auto-login potrebbe essere un’ opzione comoda.


Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.2 Personalizzazione del kernel

Guix è, al suo interno, una distribuzione basata su sorgente con sostituti (vedi Sostituti in Manuale di riferimento di GNU Guix), e come tale la compilazione di pacchetti dal loro codice sorgente è una parte prevista delle normali installazioni e aggiornamenti di pacchetti. Dato questo punto di partenza, ha senso che siano fatti sforzi per ridurre il tempo impiegato nella compilazione dei pacchetti, e i recenti cambiamenti e aggiornamenti alla costruzione e distribuzione dei sostituti continuano ad essere un argomento di discussione all’interno di Guix.

Il kernel, pur non richiedendo un’eccessiva quantità di RAM per la compilazione, impiega un tempo piuttosto lungo su una macchina media. La configurazione ufficiale del kernel, come accade con molte distribuzioni GNU/Linux, tende all’inclusività, ed è proprio questo che fa sì che la compilazione richieda così tanto tempo quando il kernel viene compilato dal sorgente.

Il kernel Linux, tuttavia, può anche essere semplicemente descritto come un normale vecchio pacchetto, e come tale può essere personalizzato proprio come qualsiasi altro pacchetto. La procedura è leggermente diversa, anche se ciò è dovuto principalmente alla natura di come è scritta la definizione del pacchetto.

La definizione del pacchetto kernel linux-libre è in realtà una procedura che crea un pacchetto.

(define* (make-linux-libre* version gnu-revision source supported-systems
 #:key
 (extra-version #f)
 ;; Una funzione che accetta un'architettura e una variante.
 ;; Vedi kernel-config per un esempio.
 (configuration-file #f)
 (defconfig "defconfig")
 (extra-options (default-extra-linux-options version )))
 ... )

L’attuale pacchetto linux-libre è per la serie 5.15.x, ed è dichiarato così:

(define-public linux-libre-5.15
 (make-linux-libre* linux-libre-5.15-version
 linux-libre-5.15-gnu-revision
 linux-libre-5.15-source
 '("x86_64-linux" "i686-linux" "armhf-linux"
 "aarch64-linux" "riscv64-linux")
 #:configuration-file kernel-config))

Qualsiasi chiave a cui non sono stati assegnati valori eredita il loro valore predefinito dalla definizione make-linux-libre. Confrontando i due snippet sopra, nota il commento al codice che si riferisce a #:configuration-file. A causa di ciò, non è effettivamente facile includere una configurazione personalizzata del kernel dalla definizione, ma non preoccuparti, ci sono altri modi per lavorare con ciò che abbiamo.

Ci sono due modi per creare un kernel con una configurazione kernel personalizzata. Il primo è fornire un defconfig standard alla procedura customize-linux. Per produrre tale file è necessario ottenere il codice sorgente Linux, creare un file .config (usando il comando make menuconfig, ad esempio) o fornirne uno che già si possiede. Dopodiché sarà necessario eseguire il comando make savedefconfig all’interno dell’albero sorgente del kernel — questo produrrà il file defconfig che useremo per compilare un kernel personalizzato.

Di seguito è riportato un esempio di pacchetto kernel.

(define-public my-linux-libre
 (package
 (inherit (customize-linux
 #:linux linux-libre
 #:defconfig
 (local-file "defconfig")))
 (name "my-linux-libre")))

Nella stessa directory del file che definisce my-linux-libre c’è un file chiamato defconfig. In questo modo puoi fornire le opzioni del kernel che desideri nel kernel risultante.

Il secondo modo per creare un kernel personalizzato è passare un nuovo valore alla parola chiave extra-options della procedura make-linux-libre. La parola chiave extra-options funziona con un’altra funzione definita subito sotto:

(define (default-extra-linux-options version )
 `(;; https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00039.html
 ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #true)
 ;; Moduli richiesti per initrd:
 ("CONFIG_NET_9P" . m)
 ("CONFIG_NET_9P_VIRTIO" . m)
 ("CONFIG_VIRTIO_BLK" . m)
 ("CONFIG_VIRTIO_NET" . m)
 ("CONFIG_VIRTIO_PCI" . m)
 ("CONFIG_VIRTIO_BALLOON" . m)
 ("CONFIG_VIRTIO_MMIO" . m)
 ("CONFIG_FUSE_FS" . m)
 ("CONFIG_CIFS" . m)
 ("CONFIG_9P_FS" . m)))
(define (config->string options)
 (string-join (map (match-lambda
 ((option . 'm)
 (string-append option "=m"))
 ((option . #true)
 (string-append option "=y"))
 ((option . #false)
 (string-append option "=n")))
 options)
 "\n"))

E nello script di configurazione personalizzato del pacchetto ‘make-linux-libre‘:

;; L'aggiunta funziona anche se l'opzione non era presente nel
;; file. L'ultima prevale se duplicata.
(let ((port (open-file ".config" "a"))
 (extra-configuration ,(config->string extra-options)))
 (display extra-configuration port)
 (close-port port))
(invoke "make" "oldconfig")

Quindi, non fornendo un file di configurazione, il .config inizia vuoto, e poi ci scriviamo la raccolta di flag che vogliamo. Ecco un altro kernel personalizzato:

(define %macbook41-full-config
 (append %macbook41-config-options
 %file-systems
 %efi-support
 %emulation
 ((@@ (gnu packages linux) default-extra-linux-options) version )))
(define-public linux-libre-macbook41
 ;; XXX: Accedere alla procedura interna 'make-linux-libre*', che è
 ;; privata e non esportata, e soggetta a modifiche future.
 ((@@ (gnu packages linux) make-linux-libre*)
 (@@ (gnu packages linux) linux-libre-version)
 (@@ (gnu packages linux) linux-libre-gnu-revision)
 (@@ (gnu packages linux) linux-libre-source)
 '("x86_64-linux")
 #:extra-version "macbook41"
 #:extra-options %macbook41-config-options))

Nell’esempio precedente %file-systems è una raccolta di flag che abilitano il supporto di diversi file system, %efi-support abilita il supporto EFI e %emulation abilita una macchina x86_64-linux a operare anche in modalità 32 bit. La procedura default-extra-linux-options è quella definita sopra, che è stata usata per evitare di perdere le opzioni di configurazione predefinite della parola chiave extra-options.

Tutto questo sembra fattibile, ma come si fa a sapere quali moduli sono richiesti per un sistema particolare? Due posti che possono essere utili nel tentativo di rispondere a questa domanda sono il Manuale Gentoo e la documentazione del kernel stesso. Dalla documentazione del kernel, sembra che make localmodconfig sia il comando che vogliamo.

Per poter effettivamente eseguire make localmodconfig, dobbiamo prima ottenere e decomprimere il codice sorgente del kernel:

tar xf $(guix build linux-libre --source)

Una volta all’interno della directory contenente il codice sorgente, esegui touch .config per creare un file .config iniziale e vuoto con cui iniziare. make localmodconfig funziona controllando ciò che hai già in .config e facendoti sapere cosa ti manca. Se il file è vuoto, ti manca tutto. Il passo successivo è eseguire:

guix shell -D linux-libre -- make localmodconfig

e annota l’output. Si noti che il file .config è ancora vuoto. L’output generalmente contiene due tipi di avvisi. I primi iniziano con "WARNING" e possono essere ignorati nel nostro caso. I secondi recitano:

il modulo pcspkr non aveva configurazioni CONFIG_INPUT_PCSPKR

Per ciascuna di queste righe, copia la porzione CONFIG_XXXX_XXXX nel .config nella directory, e aggiungi =m, così alla fine appare così:

CONFIG_INPUT_PCSPKR=m
CONFIG_VIRTIO=m

Dopo aver copiato tutte le opzioni di configurazione, esegui di nuovo make localmodconfig per assicurarti di non avere output che iniziano con “module”. Dopo tutti questi moduli specifici della macchina, ne rimangono un paio che sono anche necessari. CONFIG_MODULES è necessario affinché tu possa compilare e caricare i moduli separatamente e non avere tutto compilato nel kernel. CONFIG_BLK_DEV_SD è richiesto per la lettura da dischi rigidi. È possibile che tu abbia bisogno di altri moduli.

Questo post non intende tuttavia essere una guida alla configurazione del proprio kernel, quindi se decidi di compilare un kernel personalizzato dovrai cercare altre guide per creare un kernel adatto alle tue esigenze.

Il secondo modo per configurare il kernel sfrutta maggiormente le funzionalità di Guix e consente di condividere segmenti di configurazione tra kernel diversi. Ad esempio, tutte le macchine che usano EFI per l’avvio hanno una serie di flag di configurazione EFI di cui hanno bisogno. È probabile che tutti i kernel condividano un elenco di file system da supportare. Usando le variabili è più facile vedere a colpo d’occhio quali funzionalità sono abilitate e assicurarsi di non avere funzionalità in un kernel ma mancanti in un altro.

Rimane tuttavia non discusso il sistema initrd di Guix e la sua personalizzazione. È probabile che sia necessario modificare l’initrd su una macchina che utilizza un kernel personalizzato, poiché alcuni moduli che ci si aspetta siano compilati potrebbero non essere disponibili per l’inclusione nell’initrd.


Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.3 API immagine di Sistema Guix

Storicamente, Guix System è incentrato su una struttura operating-system. Questa struttura contiene vari campi che vanno dal bootloader e dalla dichiarazione del kernel ai servizi da installare.

A seconda della macchina di destinazione, che può variare da una macchina x86_64 standard a un piccolo computer a scheda singola ARM come la Pine64, i vincoli dell’immagine possono variare molto. I produttori di hardware imporranno diversi formati di immagine con varie dimensioni e offset delle partizioni.

Per creare immagini adatte a tutte quelle macchine, è necessaria una nuova astrazione: questo è l’obiettivo del record image. Questo record contiene tutte le informazioni necessarie per essere trasformate in un’immagine standalone, che può essere avviata direttamente su qualsiasi macchina di destinazione.

(define-record-type* <image>
 image make-image
 image?
 (name image-name ;simbolo
 (default #f))
 (format image-format) ;simbolo
 (target image-target
 (default #f))
 (size image-size ;dimensione in byte come intero
 (default 'guess))
 (operating-system image-operating-system ;<operating-system>
 (default #f))
 (partitions image-partitions ;lista di <partition>
 (default '()))
 (compression? image-compression? ;booleano
 (default #t))
 (volatile-root? image-volatile-root? ;booleano
 (default #t))
 (substitutable? image-substitutable? ;booleano
 (default #t)))

Questo record contiene il sistema operativo da istanziare. Il campo format definisce il tipo di immagine e può essere efi-raw, qcow2 o iso9660 per esempio. In futuro, potrebbe essere esteso a docker o altri tipi di immagine.

Una nuova directory nelle fonti Guix è dedicata alla definizione delle immagini. Per ora ci sono quattro file:

  • gnu/system/images/hurd.scm
  • gnu/system/images/pine64.scm
  • gnu/system/images/novena.scm
  • gnu/system/images/pinebook-pro.scm

Diamo un’occhiata a pine64.scm. Contiene la variabile pine64-barebones-os che è una definizione minima di un sistema operativo dedicata alla scheda Pine A64 LTS.

(define pine64-barebones-os
 (operating-system
 (host-name "vignemale")
 (timezone "Europe/Paris")
 (locale "en_US.utf8")
 (bootloader (bootloader-configuration
 (bootloader u-boot-pine64-lts-bootloader)
 (targets '("/dev/vda"))))
 (initrd-modules '())
 (kernel linux-libre-arm64-generic)
 (file-systems (cons (file-system
 (device (file-system-label "my-root"))
 (mount-point "/")
 (type "ext4"))
 %base-file-systems ))
 (services (cons (service agetty-service-type
 (agetty-configuration
 (extra-options '("-L")) ; nessun rilevamento portante
 (baud-rate "115200")
 (term "vt100")
 (tty "ttyS0")))
 %base-services ))))

I campi kernel e bootloader puntano a pacchetti dedicati a questa scheda.

Subito sotto, è definita anche la variabile pine64-image-type.

(define pine64-image-type
 (image-type
 (name 'pine64-raw)
 (constructor (cut image-with-os arm64-disk-image <>))))

Sta usando un record di cui non abbiamo ancora parlato, il record image-type, definito in questo modo:

(define-record-type* <image-type>
 image-type make-image-type
 image-type?
 (name image-type-name) ;simbolo
 (constructor image-type-constructor)) ;<operating-system> -> <image>

Lo scopo principale di questo record è associare un nome a una procedura che trasforma un operating-system in un’immagine. Per capire perché è necessario, diamo un’occhiata al comando che produce un’immagine da un file di configurazione operating-system:

guix system image my-os.scm

Questo comando si aspetta una configurazione operating-system ma come dovremmo indicare che vogliamo un’immagine destinata a una scheda Pine64? Dobbiamo fornire un’informazione extra, il image-type, passando il flag --image-type o -t, in questo modo:

guix system image --image-type=pine64-raw my-os.scm

Questo parametro image-type punta al pine64-image-type definito sopra. Quindi, il operating-system dichiarato in my-os.scm verrà applicato alla procedura (cut image-with-os arm64-disk-image <>) per trasformarlo in un’immagine.

L’immagine risultante si presenta così:

(image
 (format 'disk-image)
 (target "aarch64-linux-gnu")
 (operating-system my-os)
 (partitions
 (list (partition
 (inherit root-partition)
 (offset root-offset)))))

che è l’aggregazione del operating-system definito in my-os.scm al record arm64-disk-image.

Ma basta follia Scheme. Cosa porta questa API immagine all’utente Guix?

Si può eseguire:

mathieu@cervin:~$ guix system --list-image-types
I tipi di immagine disponibili sono:
 - unmatched-raw
 - rock64-raw
 - pinebook-pro-raw
 - pine64-raw
 - novena-raw
 - hurd-raw
 - hurd-qcow2
 - qcow2
 - iso9660
 - uncompressed-iso9660
 - tarball
 - efi-raw
 - mbr-raw
 - docker
 - wsl2
 - raw-with-offset
 - efi32-raw

e scrivendo un file operating-system basato su pine64-barebones-os, puoi personalizzare la tua immagine secondo le tue preferenze in un file (my-pine-os.scm) come questo:

(use-modules (gnu services linux)
 (gnu system images pine64))
(let ((base-os pine64-barebones-os))
 (operating-system
 (inherit base-os)
 (timezone "America/Indiana/Indianapolis")
 (services
 (cons
 (service earlyoom-service-type
 (earlyoom-configuration
 (prefer-regexp "icecat|chromium")))
 (operating-system-user-services base-os)))))

esegui:

guix system image --image-type=pine64-raw my-pine-os.scm

o,

guix system image --image-type=hurd-raw my-hurd-os.scm

per ottenere un’immagine che può essere scritta direttamente su un disco rigido e avviata.

Senza cambiare nulla in my-hurd-os.scm, chiamando:

guix system image --image-type=hurd-qcow2 my-hurd-os.scm

produrrà invece un’immagine Hurd QEMU.


Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.4 Utilizzo di chiavi di sicurezza

L’uso delle chiavi di sicurezza può migliorare la tua sicurezza fornendo una seconda fonte di autenticazione che non può essere facilmente rubata o copiata, almeno per un avversario remoto (qualcosa che hai), al segreto principale (una passphrase – qualcosa che sai), riducendo il rischio di impersonificazione.

L’esempio di configurazione dettagliato di seguito mostra quali configurazioni minime devono essere apportate al tuo sistema Guix per consentire l’uso di una chiave di sicurezza Yubico. Si spera che la configurazione possa essere utile anche per altre chiavi di sicurezza, con piccole modifiche.

3.4.1 Configurazione per l’uso come autenticatore a due fattori (2FA)

Per essere utilizzabile, le regole udev del sistema dovrebbero essere estese con regole specifiche per la chiave. Il seguente mostra come estendere le tue regole udev con il file di regole udev lib/udev/rules.d/70-u2f.rules fornito dal pacchetto libfido2 dal modulo (gnu packages security-token) e aggiungere il tuo utente al gruppo ‘"plugdev"’ che utilizza:

(use-package-modules ... security-token ... )
...
(operating-system
 ...
 (users (cons* (user-account
 (name "tuo-utente")
 (group "users")
 (supplementary-groups
		'("wheel" "netdev" "audio" "video"
 "plugdev")) ;<- gruppo di sistema aggiunto
 (home-directory "/home/tuo-utente"))
 %base-user-accounts ))
 ...
 (services
 (cons*
 ...
 (udev-rules-service 'fido2 libfido2 #:groups '("plugdev")))))

Dopo aver riconfigurato il sistema e aver effettuato nuovamente l’accesso alla sessione grafica in modo che il nuovo gruppo sia effettivo per il tuo utente, puoi verificare che la tua chiave sia utilizzabile avviando:

guix shell ungoogled-chromium -- chromium chrome://settings/securityKeys

e verificando che la chiave di sicurezza possa essere resettata tramite il menu “Reset your security key”. Se funziona, congratulazioni, la tua chiave di sicurezza è pronta per essere utilizzata con applicazioni che supportano l’autenticazione a due fattori (2FA).

3.4.2 Disabilitazione della generazione di codici OTP per una Yubikey

Se utilizzi una chiave di sicurezza Yubikey e sei irritato dai codici OTP spuri che genera quando tocchi involontariamente la chiave (ad esempio, facendoti diventare uno spammer nel canale ‘#guix’ mentre discuti dal tuo client IRC preferito!), puoi disabilitarlo tramite il seguente comando ykman:

guix shell python-yubikey-manager -- ykman config usb --force --disable OTP

In alternativa, potresti usare il comando ykman-gui fornito dal pacchetto yubikey-manager-qt e disabilitare completamente l’applicazione ‘OTP’ per l’interfaccia USB oppure, dalla vista ‘Applications -> OTP’, eliminare la configurazione dello slot 1, che viene preconfigurata con l’applicazione Yubico OTP.

3.4.3 Richiedere una Yubikey per aprire un database KeePassXC

L’applicazione KeePassXC, gestore di password, supporta le Yubikey, ma richiede l’installazione di regole udev per il tuo sistema Guix e una certa configurazione dell’applicazione Yubico OTP sulla chiave.

Il file di regole udev necessario proviene dal pacchetto yubikey-personalization, e può essere installato così:

(use-package-modules ... security-token ... )
...
(operating-system
 ...
 (services
 (cons*
 ...
 (udev-rules-service 'yubikey yubikey-personalization))))

Dopo aver riconfigurato il sistema (e ricollegato la tua Yubikey), dovrai poi configurare l’applicazione di sfida/risposta OTP della tua Yubikey sullo slot 2, che è ciò che KeePassXC usa. È facile farlo tramite lo strumento di configurazione grafica Yubikey Manager, che può essere invocato con:

guix shell yubikey-manager-qt -- ykman-gui

Innanzitutto, assicurati che ‘OTP’ sia abilitato nella scheda ‘Interfacce’, quindi vai a ‘Applicazioni -> OTP’ e fai clic sul pulsante ‘Configura’ nella sezione ‘Tocco lungo (Slot 2)’. Seleziona ‘Challenge-response’, inserisci o genera una chiave segreta e fai clic sul pulsante ‘Fine’. Se hai una seconda Yubikey che desideri utilizzare come backup, dovresti configurarla nello stesso modo, utilizzando la stessa chiave segreta.

La tua Yubikey dovrebbe ora essere rilevata da KeePassXC. Può essere aggiunta a un database navigando nel menu ‘Database -> Sicurezza database...’ di KeePassXC, quindi facendo clic sul pulsante ‘Aggiungi protezione aggiuntiva...’, quindi su ‘Aggiungi Challenge-Response’, selezionando la chiave di sicurezza dal menu a discesa e facendo clic sul pulsante ‘OK’ per completare la configurazione.


Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.5 Processo mcron per DNS dinamico

Se il tuo ISP (Internet Service Provider) fornisce solo indirizzi IP dinamici, può essere utile configurare un servizio DNS (Domain Name System) dinamico (noto anche come DDNS (Dynamic DNS)) per associare un nome host statico a un indirizzo IP pubblico ma dinamico (spesso variabile). Esistono diversi servizi che possono essere utilizzati a questo scopo; nel seguente job mcron, DuckDNS viene utilizzato. Dovrebbe funzionare anche con altri servizi DNS dinamici che offrono un’interfaccia simile per aggiornare l’ indirizzo IP, come https://freedns.afraid.org/, con piccole modifiche.

Il job mcron è fornito di seguito, dove DOMAIN dovrebbe essere sostituito con il tuo prefisso di dominio, e il token fornito da DuckDNS associato a DOMAIN aggiunto al file /etc/duckdns/DOMAIN.token.

(define duckdns-job
 ;; Aggiorna l'IP del dominio personale ogni 5 minuti.
 #~(job '(next-minute (range 0 60 5))
	 #$(program-file
 "duckdns-update"
 (with-extensions (list guile-gnutls) ;richiesto da (web client)
 #~(begin
 (use-modules (ice-9 textual-ports)
 (web client))
 (let ((token (string-trim-both
 (call-with-input-file "/etc/duckdns/DOMAIN.token"
 get-string-all )))
 (query-template (string-append "https://www.duckdns.org/"
 "update?domains=DOMAIN"
 "&token=~a&ip=")))
 (http-get (format #f query-template token))))))
 "duckdns-update"
 #:user "nobody"))

Il job deve quindi essere aggiunto all’elenco dei job mcron per il tuo sistema, usando qualcosa come:

(operating-system
 (services
 (cons* (service mcron-service-type
 (mcron-configuration
 (jobs (list duckdns-job ... ))))
 ...
 %base-services )))

Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.6 Connessione a una VPN Wireguard

Per connettersi a un server VPN Wireguard è necessario che il modulo del kernel sia caricato in memoria e un pacchetto che fornisca strumenti di rete che lo supportino (ad esempio, wireguard-tools o network-manager).

Ecco un esempio di configurazione per Linux-Libre < 5.6, dove il modulo è esterno all’albero e deve essere caricato manualmente—le revisioni successive del kernel lo hanno integrato e quindi non necessitano di tale configurazione:

(use-modules (gnu))
(use-service-modules desktop)
(use-package-modules vpn)
(operating-system
 ;; ...
 (services (cons (simple-service 'wireguard-module
 kernel-module-loader-service-type
 '("wireguard"))
 %desktop-services ))
 (packages (cons wireguard-tools %base-packages))
 (kernel-loadable-modules (list wireguard-linux-compat)))

Dopo aver riconfigurato e riavviato il sistema, puoi usare gli strumenti Wireguard o NetworkManager per connetterti a un server VPN.

3.6.1 Utilizzo degli strumenti Wireguard

Per testare la tua configurazione Wireguard è comodo usare wg-quick. Basta dargli un file di configurazione wg-quick up ./wg0.conf; o metterlo in /etc/wireguard ed eseguire wg-quick up wg0 invece.

Nota: Si noti che l’autore ha descritto questo comando come: "[...] uno script bash molto veloce e sporco [...]".

3.6.2 Utilizzo di NetworkManager

Grazie al supporto di NetworkManager per Wireguard, possiamo connetterci alla nostra VPN usando il comando nmcli. Fino a questo punto, questa guida presuppone che stai usando il servizio Network Manager fornito da %desktop-services. Altrimenti devi regolare l’elenco dei tuoi servizi per caricare network-manager-service-type e riconfigurare il tuo sistema Guix.

Per importare la tua configurazione VPN, esegui il comando nmcli import:

# nmcli connection import type wireguard file wg0.conf
Connessione 'wg0' (edbee261-aa5a-42db-b032-6c7757c60fde) aggiunta con successo

Questo creerà un file di configurazione in /etc/NetworkManager/ wg0.nmconnection. Quindi connettiti al server Wireguard:

$ nmcli connection up wg0
Connessione attivata con successo (percorso attivo D-Bus: /org/freedesktop/
NetworkManager/ActiveConnection/6)

Per impostazione predefinita, NetworkManager si connetterà automaticamente all’avvio del sistema. Per modificare questo comportamento, devi modificare la tua configurazione:

# nmcli connection modify wg0 connection.autoconnect no

Per informazioni più specifiche su NetworkManager e Wireguard, vedi questo post di Thaller.


Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.7 Personalizzazione di un Window Manager


3.7.1 StumpWM

Potresti installare StumpWM con un sistema Guix aggiungendo i pacchetti stumpwm e opzionalmente `(,stumpwm "lib") a un file di configurazione di sistema, ad esempio: /etc/config.scm.

Una configurazione di esempio può apparire così:

(use-modules (gnu))
(use-package-modules wm)
(operating-system
 ;; ...
 (packages (append (list sbcl stumpwm `(,stumpwm "lib"))
 %base-packages)))

Per impostazione predefinita StumpWM utilizza i font X11, che potrebbero essere piccoli o pixelati sul tuo sistema. Puoi risolvere questo problema installando il modulo Lisp di StumpWM contrib sbcl-ttf-fonts, aggiungendolo ai pacchetti di sistema Guix:

(use-modules (gnu))
(use-package-modules fonts wm)
(operating-system
 ;; ...
 (packages (append (list sbcl stumpwm `(,stumpwm "lib"))
 sbcl-ttf-fonts font-dejavu %base-packages)))

Quindi devi aggiungere il seguente codice a un file di configurazione di StumpWM ~/.stumpwm.d/init.lisp:

(require :ttf-fonts)
(setf xft:*font-dirs* '("/run/current-system/profile/share/fonts/"))
(setf clx-truetype:+font-cache-filename+ (concat (getenv "HOME")
 "/.fonts/font-cache.sexp"))
(xft:cache-fonts)
(set-font (make-instance 'xft:font :family "DejaVu Sans Mono"
 :subfamily "Book" :size 11))

3.7.2 Blocco sessione

A seconda del tuo ambiente, il blocco dello schermo della tua sessione potrebbe essere integrato o potresti doverlo configurare tu stesso. Se usi un ambiente desktop come GNOME o KDE, di solito è integrato. Se usi un semplice window manager come StumpWM o EXWM, potresti doverlo configurare tu stesso.


3.7.2.1 Xorg

Se usi Xorg, puoi usare l’utility xss-lock per bloccare lo schermo della tua sessione. xss-lock è attivato da DPMS che da Xorg 1.8 è auto-rilevato e abilitato se ACPI è anche abilitato durante l’esecuzione del kernel.

Per usare xss-lock, puoi semplicemente eseguirlo e metterlo in background prima di avviare il tuo window manager da, ad esempio, il tuo ~/.xsession:

xss-lock -- slock &
exec stumpwm

In questo esempio, xss-lock usa slock per bloccare effettivamente lo schermo quando lo ritiene opportuno, ad esempio quando sospendi il tuo dispositivo.

Affinché slock possa essere un blocco schermo per la sessione grafica, deve essere reso setuid-root in modo da poter autenticare gli utenti, e ha bisogno di un servizio PAM. Ciò può essere ottenuto aggiungendo il seguente servizio al tuo config.scm:

(service screen-locker-service-type
 (screen-locker-configuration
 (name "slock")
 (program (file-append slock "/bin/slock"))))

Se blocchi manualmente lo schermo, ad esempio chiamando direttamente slock quando vuoi bloccare lo schermo ma non sospenderlo, è una buona idea notificare xss-lock in modo che non si crei confusione. Ciò può essere fatto eseguendo xset s activate immediatamente prima di eseguire slock.


Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.8 Eseguire Guix su un Server Linode

Per eseguire Guix su un server ospitato da Linode, inizia con un server Debian consigliato. Consigliamo di usare la distro predefinita come modo per avviare Guix. Crea le tue chiavi SSH.

ssh-keygen

Assicurati di aggiungere la tua chiave SSH per un facile accesso al server remoto. Questo è facilmente fatto tramite l’interfaccia grafica di Linode per l’aggiunta di chiavi SSH. Vai al tuo profilo e clicca su aggiungi chiave SSH. Copia al suo interno l’output di:

cat ~/.ssh/<nomeutente>_rsa.pub

Spegni il Linode.

Nella scheda Storage di Linode, ridimensiona il disco Debian per renderlo più piccolo. Si consigliano 30 GB di spazio libero. Quindi clicca su "Aggiungi un disco" e compila il modulo con quanto segue:

  • Etichetta: "Guix"
  • Filesystem: ext4
  • Impostalo alla dimensione rimanente

Nella scheda Configurazioni, premi "Modifica" sul profilo Debian predefinito. Sotto "Assegnazione Dispositivo a Blocchi" clicca "Aggiungi un Dispositivo". Dovrebbe essere /dev/sdc e puoi selezionare il disco "Guix". Salva le modifiche.

Ora "Aggiungi una Configurazione", con quanto segue:

  • Etichetta: Guix
  • Kernel:GRUB 2 (è in fondo! Questo passaggio è IMPORTANTE!)
  • Assegnazione dispositivo a blocchi:
  • /dev/sda: Guix
  • /dev/sdb: swap
  • Dispositivo root: /dev/sda
  • Disattiva tutti gli assistenti di filesystem/avvio

Ora riaccendilo, avviando con la configurazione Debian. Una volta in esecuzione, connettiti al tuo server via ssh con ssh root@<il-tuo-IP-server-qui>. (Puoi trovare l’indirizzo IP del tuo server nella sezione Riepilogo di Linode.) Ora puoi eseguire i passaggi per "installare Guix da vedi Installazione binaria in GNU Guix":

sudo apt-get install gpg
wget https://sv.gnu.org/people/viewgpg.php?user_id=15145 -qO - | gpg --import -
wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
chmod +x guix-install.sh
./guix-install.sh
guix pull

Ora è il momento di scrivere una configurazione per il server. Le informazioni chiave sono qui sotto. Salva il file risultante come guix-config.scm.

(use-modules (gnu)
 (guix modules))
(use-service-modules networking
 ssh)
(use-package-modules admin
 package-management
 ssh
 tls)
(operating-system
 (host-name "my-server")
 (timezone "America/New_York")
 (locale "en_US.UTF-8")
 ;; Questo codice strambo genererà il grub.cfg
 ;; senza installare il bootloader grub sul disco.
 (bootloader (bootloader-configuration
 (bootloader
 (bootloader
 (inherit grub-bootloader)
 (installer #~(const #true))))))
 (file-systems (cons (file-system
 (device "/dev/sda")
 (mount-point "/")
 (type "ext4"))
 %base-file-systems ))
 (swap-devices (list "/dev/sdb"))
 (initrd-modules (cons "virtio_scsi" ; Necessario per trovare il disco
 %base-initrd-modules ))
 (users (cons (user-account
 (name "janedoe")
 (group "users")
 ;; Aggiungendo l'account al gruppo "wheel"
 ;; lo rende un sudoer.
 (supplementary-groups '("wheel"))
 (home-directory "/home/janedoe"))
 %base-user-accounts ))
 (packages (cons* openssh-sans-x
 %base-packages))
 (services (cons*
 (service dhcp-client-service-type )
 (service openssh-service-type
 (openssh-configuration
 (openssh openssh-sans-x)
 (password-authentication? #false)
 (authorized-keys
 `(("janedoe" ,(local-file "janedoe_rsa.pub"))
 ("root" ,(local-file "janedoe_rsa.pub"))))))
 %base-services )))

Sostituisci i seguenti campi nella configurazione sopra:

(host-name "il-mio-server") ; sostituisci con il nome del tuo server
; se hai scelto un server linode fuori dagli Stati Uniti, allora
; usa tzselect per trovare una stringa di fuso orario corretta
(timezone "America/New_York") ; se necessario sostituisci il fuso orario
(name "janedoe") ; sostituisci con il tuo nome utente
("janedoe" ,(local-file "janedoe_rsa.pub")) ; sostituisci con la tua chiave ssh
("root" ,(local-file "janedoe_rsa.pub")) ; sostituisci con la tua chiave ssh

L’ultima riga nell’esempio sopra ti permette di accedere al server come root e impostare la password iniziale di root (vedi la nota alla fine di questa ricetta su l’accesso come root). Dopo aver fatto ciò, puoi eliminare quella riga dalla tua configurazione e riconfigurare per impedire l’accesso come root.

Copia la tua chiave pubblica ssh (es: ~/.ssh/id_rsa.pub) come <il-tuo-nomeutente-qui>_rsa.pub e metti guix-config.scm nella stessa directory. In un nuovo terminale esegui questi comandi.

sftp root@<indirizzo ip del server remoto>
put /percorso/ai/files/<nomeutente>_rsa.pub .
put /percorso/ai/files/guix-config.scm .

Nel tuo primo terminale, monta l’unità guix:

mkdir /mnt/guix
mount /dev/sdc /mnt/guix

A causa del modo in cui abbiamo configurato la sezione del bootloader di guix-config.scm, solo il file di configurazione di grub verrà installato. Quindi, dobbiamo copiare parte del resto del GRUB già installato sul sistema Debian:

mkdir -p /mnt/guix/boot/grub
cp -r /boot/grub/* /mnt/guix/boot/grub/

Ora inizializza l’installazione di Guix:

guix system init guix-config.scm /mnt/guix

Ok, spegnilo! Ora dalla console di Linode, seleziona boot e seleziona "Guix".

Una volta avviato, dovresti essere in grado di accedere via SSH! (La configurazione del server sarà cambiata però.) Potresti incontrare un errore come:

$ ssh root@<indirizzo ip del server>
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  ATTENZIONE: L'IDENTIFICAZIONE DELL'HOST REMOTO È CAMBIATA! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ È POSSIBILE CHE QUALCUNO STIA FACENDO QUALCOSA DI BRUTTO!
Qualcuno potrebbe intercettarti in questo momento (attacco man-in-the-middle)!
È anche possibile che una chiave host sia stata appena cambiata.
L'impronta digitale della chiave ECDSA inviata dall'host remoto è
SHA256:0B+wp33w57AnKQuHCvQP0+ZdKaqYrI/kyU7CfVbS7R4.
Si prega di contattare l'amministratore del sistema.
Aggiungi la chiave host corretta in /home/joshua/.ssh/known_hosts per eliminare questo messaggio.
Chiave ECDSA offensiva in /home/joshua/.ssh/known_hosts:3
La chiave host ECDSA per 198.58.98.76 è cambiata e hai richiesto un controllo rigoroso.
Verifica della chiave host fallita.

Elimina il file ~/.ssh/known_hosts oppure elimina la riga incriminata che inizia con l’indirizzo IP del tuo server.

Assicurati di impostare la tua password e quella di root.

ssh root@<indirizzo ip remoto>
passwd ; per la password di root
passwd <nomeutente> ; per la password utente

Potresti non essere in grado di eseguire i comandi sopra a questo punto. Se hai problemi ad accedere in remoto alla tua macchina Linode via SSH, potresti ancora dover impostare inizialmente la password di root e dell’utente cliccando sull’opzione “Launch Console” nel tuo Linode. Scegli “Glish” invece di “Weblish”. Ora dovresti essere in grado di accedere alla macchina tramite ssh.

Evviva! A questo punto puoi spegnere il server, eliminare il disco Debian, e ridimensionare il Guix al resto della dimensione. Congratulazioni!

A proposito, se lo salvi come immagine disco proprio a questo punto, avrai facilità a creare nuove immagini Guix! Potrebbe essere necessario ridurre la dimensione dell’immagine Guix a 6144MB, per salvarla come immagine. Quindi puoi ridimensionarla di nuovo a la dimensione massima.


Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.9 Eseguire Guix su un Server Kimsufi

Per eseguire Guix su un server ospitato da Kimsufi, clicca sulla scheda netboot, quindi seleziona rescue64-pro e riavvia.

OVH ti invierà via email le credenziali necessarie per accedere via ssh a un sistema Debian.

Ora puoi eseguire i passaggi per "installare Guix da vedi Installazione binaria in GNU Guix":

wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
chmod +x guix-install.sh
./guix-install.sh
guix pull

Partiziona i dischi e formattali, prima ferma l’array raid:

mdadm --stop /dev/md127
mdadm --zero-superblock /dev/sda2 /dev/sdb2

Quindi azzera i dischi e configura le partizioni, creeremo un array RAID 1.

wipefs -a /dev/sda
wipefs -a /dev/sdb
parted /dev/sda --align=opt -s -m -- mklabel gpt
parted /dev/sda --align=opt -s -m -- \
 mkpart bios_grub 1049kb 512MiB \
 set 1 bios_grub on
parted /dev/sda --align=opt -s -m -- \
 mkpart primary 512MiB -512MiB
 set 2 raid on
parted /dev/sda --align=opt -s -m -- mkpart primary linux-swap 512MiB 100%
parted /dev/sdb --align=opt -s -m -- mklabel gpt
parted /dev/sdb --align=opt -s -m -- \
 mkpart bios_grub 1049kb 512MiB \
 set 1 bios_grub on
parted /dev/sdb --align=opt -s -m -- \
 mkpart primary 512MiB -512MiB \
 set 2 raid on
parted /dev/sdb --align=opt -s -m -- mkpart primary linux-swap 512MiB 100%

Crea l’array:

mdadm --create /dev/md127 --level=1 --raid-disks=2 \
 --metadata=0.90 /dev/sda2 /dev/sdb2

Ora crea i file system sulle partizioni pertinenti, prima le partizioni di avvio:

mkfs.ext4 /dev/sda1
mkfs.ext4 /dev/sdb1

Quindi la partizione root:

mkfs.ext4 /dev/md127

Inizializza le partizioni di swap:

mkswap /dev/sda3
swapon /dev/sda3
mkswap /dev/sdb3
swapon /dev/sdb3

Monta l’unità guix:

mkdir /mnt/guix
mount /dev/md127 /mnt/guix

Ora è il momento di scrivere un file di dichiarazione del sistema operativo os.scm; ecco un esempio:

(use-modules (gnu) (guix))
(use-service-modules networking ssh vpn virtualization sysctl admin mcron)
(use-package-modules ssh tls tmux vpn virtualization)
(operating-system
 (host-name "kimsufi")
 (bootloader (bootloader-configuration
	 (bootloader grub-bootloader)
	 (targets (list "/dev/sda" "/dev/sdb"))
	 (terminal-outputs '(console))))
 ;; Aggiungi un modulo del kernel per RAID-1 (alias "mirror").
 (initrd-modules (cons* "raid1" %base-initrd-modules ))
 (mapped-devices
 (list (mapped-device
 (source (list "/dev/sda2" "/dev/sdb2"))
 (target "/dev/md127")
 (type raid-device-mapping ))))
 (swap-devices
 (list (swap-space
 (target "/dev/sda3"))
 (swap-space
 (target "/dev/sdb3"))))
 (issue
 ;; Contenuti predefiniti per /etc/issue.
 "\
Questo è il sistema GNU su Kimsufi. Benvenuto.\n")
 (file-systems (cons* (file-system
		 (mount-point "/")
		 (device "/dev/md127")
		 (type "ext4")
		 (dependencies mapped-devices))
		 %base-file-systems ))
 (users (cons (user-account
	 (name "guix")
	 (comment "guix")
	 (group "users")
	 (supplementary-groups '("wheel"))
	 (home-directory "/home/guix"))
	 %base-user-accounts ))
 (sudoers-file
 (plain-file "sudoers" "\
root ALL=(ALL) ALL
%wheel ALL=(ALL) ALL
guix ALL=(ALL) NOPASSWD:ALL\n"))
 ;; Pacchetti installati globalmente.
 (packages (cons* tmux gnutls wireguard-tools %base-packages))
 (services
 (cons*
 (service static-networking-service-type
	 (list (static-networking
		 (addresses (list (network-address
				 (device "enp3s0")
				 (value "indirizzo-ip-server/24"))))
		 (routes (list (network-route
				 (destination "default")
				 (gateway "server-gateway"))))
		 (name-servers '("213.186.33.99")))))
 (service unattended-upgrade-service-type )
 (service openssh-service-type
	 (openssh-configuration
	 (openssh openssh-sans-x)
	 (permit-root-login #f)
	 (authorized-keys
	 `(("guix" ,(plain-file "ssh-key-name.pub"
 "contenuto-chiave-pubblica-ssh"))))))
 (modify-services %base-services
 (sysctl-service-type
 config =>
 (sysctl-configuration
	(settings (append '(("net.ipv6.conf.all.autoconf" . "0")
			 ("net.ipv6.conf.all.accept_ra" . "0"))
			 %default-sysctl-settings ))))))))

Non dimenticare di sostituire le variabili indirizzo-ip-server, server-gateway, nome-chiave-ssh e contenuto-chiave-pubblica-ssh con i tuoi valori.

Il gateway è l’ultimo IP utilizzabile nel tuo blocco, quindi se hai un server con un IP di ‘37.187.79.10’ allora il suo gateway sarà ‘37.187.79.254’.

Trasferisci il file di dichiarazione del tuo sistema operativo os.scm sul server tramite i comandi scp o sftp.

Ora non resta che installare Guix con un guix system init e riavviare.

Tuttavia, dobbiamo prima configurare un chroot, perché la partizione root del sistema di recupero è montata su una partizione aufs e se provi a installare Guix fallirà al passaggio di installazione di GRUB lamentandosi del percorso canonico di "aufs".

Installa i pacchetti che verranno usati nel chroot:

guix install bash-static parted util-linux-with-udev coreutils guix

Quindi esegui quanto segue per creare le directory necessarie per il chroot:

cd /mnt && \
mkdir -p bin etc gnu/store root/.guix-profile/ root/.config/guix/current \
 var/guix proc sys dev

Copia il resolv.conf dell’host nel chroot:

cp /etc/resolv.conf etc/

Monta i dispositivi a blocchi, lo store e il suo database e la configurazione attuale di guix:

mount --rbind /proc /mnt/proc
mount --rbind /sys /mnt/sys
mount --rbind /dev /mnt/dev
mount --rbind /var/guix/ var/guix/
mount --rbind /gnu/store gnu/store/
mount --rbind /root/.config/ root/.config/
mount --rbind /root/.guix-profile/bin/ bin
mount --rbind /root/.guix-profile root/.guix-profile/

Chroot in /mnt e installa il sistema:

chroot /mnt/ /bin/bash
guix system init /root/os.scm /guix

Infine, dall’interfaccia utente web (UI), cambia ‘netboot’ in ‘avvio da disco’ e riavvia (anche dall’interfaccia utente web).

Aspetta qualche minuto e prova a connetterti via ssh con ssh guix@indirizzo-ip-server> -i path-to-your-ssh-key

Dovresti avere un sistema Guix attivo e funzionante su Kimsufi; congratulazioni!


Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.10 Configurazione di un bind mount

Per montare con bind un file system, è necessario prima impostare alcune definizioni prima della sezione operating-system della definizione del sistema. In questo esempio monteremo con bind una cartella da un disco rotante su /tmp, per risparmiare usura sul SSD primario, senza dedicare un’intera partizione da montare come /tmp.

Innanzitutto, l’unità sorgente che ospita la cartella che desideriamo montare con bind dovrebbe essere definita, in modo che il mount bind possa dipendere da essa.

(define source-drive ;; "source-drive" può essere chiamato come vuoi.
 (file-system
 (device (uuid "UUID va qui"))
 (mount-point "/percorso-al-disco-rotante-va-qui")
 (type "ext4"))) ;Assicurati di impostarlo al tipo appropriato per la tua unità.

La cartella sorgente deve essere definita anche, in modo che guix sappia che non è un dispositivo a blocchi regolare, ma una cartella.

;; "source-directory" può essere qualsiasi nome di variabile valido.
(define (%source-directory) "/percorso-al-disco-rotante-va-qui/tmp")

Infine, all’interno della definizione file-systems, dobbiamo aggiungere il mount stesso.

(file-systems (cons*
 ...<altre unità omesse per chiarezza>...
 ;; Deve corrispondere al nome che hai dato all'unità sorgente nella definizione precedente.
 source-drive
 (file-system
 ;; Assicurati che "source-directory" corrisponda alla tua definizione precedente.
 (device (%source-directory))
 (mount-point "/tmp")
 ;; Stiamo montando una cartella, non una partizione, quindi questo tipo deve essere "none"
 (type "none")
 (flags '(bind-mount))
 ;; Assicurati che "source-drive" corrisponda al nome che hai dato alla variabile per l'unità.
 (dependencies (list source-drive))
 )
 ...<altre unità omesse per chiarezza>...
 ))

Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.11 Ottenere sostituti da Tor

Il demone Guix può usare un proxy HTTP per ottenere i sostituti, qui lo stiamo configurando per ottenerli tramite Tor.

Avviso: Non tutto il traffico del demone Guix passerà attraverso Tor! Solo HTTP/HTTPS sarà proxato; FTP, protocollo Git, SSH, ecc. le connessioni passeranno comunque attraverso il clearnet. Ancora una volta, questa configurazione non è a prova di errore, parte del tuo traffico non sarà affatto instradato da Tor. Usala a tuo rischio e pericolo.

Si noti inoltre che la procedura qui descritta si applica solo alla sostituzione di pacchetti. Quando si aggiorna la distribuzione guix con guix pull, è comunque necessario utilizzare torsocks se si desidera instradare la connessione ai server del repository git di guix tramite Tor.

Il server di sostituzione di Guix è disponibile come servizio Onion, se vuoi usarlo per ottenere i tuoi sostituti tramite Tor, configura il tuo sistema come segue:

(use-modules (gnu))
(use-service-module base networking)
(operating-system
 ...
 (services
 (cons
 (service tor-service-type
 (tor-configuration
 (config-file (plain-file "tor-config"
 "HTTPTunnelPort 127.0.0.1:9250"))))
 (modify-services %base-services
 (guix-service-type
 config => (guix-configuration
 (inherit config)
 ;; servizio Onion di ci.guix.gnu.org
 (substitute-urls "\
https://4zwzi66wwdaalbhgnix55ea3ab4pvvw66ll2ow53kjub6se4q2bclcyd.onion")
 (http-proxy "http://localhost:9250")))))))

Questo manterrà un processo tor in esecuzione che fornisce un tunnel HTTP CONNECT che sarà usato da guix-daemon. Il demone può usare altri protocolli oltre a HTTP(S) per ottenere risorse remote, le richieste che usano tali protocolli non passeranno attraverso Tor poiché stiamo impostando solo un tunnel HTTP qui. Si noti che substitutes-urls sta usando HTTPS e non HTTP o non funzionerà, questa è una limitazione del tunnel di Tor; potresti voler usare privoxy invece per evitare tali limitazioni.

Se non vuoi ottenere sempre sostituti tramite Tor ma usarlo solo a volte, allora salta la guix-configuration. Quando vuoi ottenere un sostituto dal tunnel Tor esegui:

sudo herd set-http-proxy guix-daemon http://localhost:9250
guix build \
 --substitute-urls=https://4zwzi66wwdaalbhgnix55ea3ab4pvvw66ll2ow53kjub6se4q2bclcyd.onion …

Successivo: , Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.12 Configurazione di NGINX con Lua

NGINX potrebbe essere esteso con script Lua.

Guix fornisce il servizio NGINX con la capacità di caricare il modulo Lua e specifici pacchetti Lua, e di rispondere alle richieste valutando gli script Lua.

Il seguente esempio dimostra la definizione del sistema con la configurazione per valutare lo script Lua index.lua su richiesta HTTP all’endpoint http://localhost/hello:

local shell = require "resty.shell"
local stdin = ""
local timeout = 1000 -- ms
local max_size = 4096 -- byte
local ok, stdout, stderr, reason, status =
 shell.run([[/run/current-system/profile/bin/ls /tmp]], stdin, timeout, max_size)
ngx.say(stdout)
(use-modules (gnu))
(use-service-modules #;... web)
(use-package-modules #;... lua)
(operating-system
 ;; ...
 (services
 ;; ...
 (service nginx-service-type
 (nginx-configuration
 (modules
 (list
 (file-append nginx-lua-module "/etc/nginx/modules/ngx_http_lua_module.so")))
 (lua-package-path (list lua-resty-core
 lua-resty-lrucache
 lua-resty-signal
 lua-tablepool
 lua-resty-shell))
 (lua-package-cpath (list lua-resty-signal))
 (server-blocks
 (list (nginx-server-configuration
 (server-name '("localhost"))
 (listen '("80"))
 (root "/etc")
 (locations (list
 (nginx-location-configuration
 (uri "/hello")
 (body (list #~(format #f "content_by_lua_file ~s;"
 #$(local-file "index.lua"))))))))))))))

Precedente: , Su: Configurazione di sistema [Contenuti][Indice]

3.13 Server musicale con audio Bluetooth

MPD, il Music Player Daemon, è un’applicazione flessibile lato server per riprodurre musica. I programmi client su diverse macchine della rete — un telefono cellulare, un laptop, una workstation desktop — possono connettersi ad esso per controllare la riproduzione di file audio dalla tua collezione musicale locale. MPD decodifica i file audio e li riproduce su una o più uscite.

Per impostazione predefinita MPD riprodurrà sul dispositivo audio predefinito. Nell’esempio seguente rendiamo le cose un po’ più interessanti impostando un server musicale headless. Non ci sarà interfaccia grafica utente, nessun demone Pulseaudio, e nessuna uscita audio locale. Invece configureremo MPD con due uscite: un altoparlante bluetooth e un server web per servire flussi audio a qualsiasi lettore multimediale in streaming.

Il Bluetooth è spesso piuttosto frustrante da configurare. Dovrai accoppiare il tuo dispositivo Bluetooth e assicurarti che il dispositivo sia connesso automaticamente non appena si accende. Il servizio di sistema Bluetooth restituito dalla procedura bluetooth-service fornisce l’infrastruttura necessaria per configurarlo.

Riconfigura il tuo sistema con almeno i seguenti servizi e pacchetti:

(operating-system
 ;; ...
 (packages (cons* bluez bluez-alsa
 %base-packages))
 (services
 ;; ...
 (dbus-service #:services (list bluez-alsa))
 (bluetooth-service #:auto-enable? #t)))

Avvia il servizio bluetooth e poi usa bluetoothctl per scandire i dispositivi Bluetooth. Prova a identificare il tuo altoparlante Bluetooth e ricava il suo ID dispositivo dalla lista risultante di dispositivi che è indubbiamente dominata da un’incredibile varietà di gadget di automazione domestica dei tuoi vicini. Questo deve essere fatto solo una volta:

$ bluetoothctl 
[NEW] Controller 00:11:22:33:95:7F BlueZ 5.40 [default]
[bluetooth]# power on
[bluetooth]# Changing power on succeeded
[bluetooth]# agent on
[bluetooth]# Agente registrato
[bluetooth]# default-agent
[bluetooth]# Richiesta agente predefinito riuscita
[bluetooth]# scan on
[bluetooth]# Rilevamento avviato
[CHG] Controller 00:11:22:33:95:7F Rilevamento: sì
[NEW] Dispositivo AA:BB:CC:A4:AA:CD Il mio altoparlante Bluetooth
[NEW] Dispositivo 44:44:FF:2A:20:DC TV del mio vicino
…
[bluetooth]# pair AA:BB:CC:A4:AA:CD
Tentativo di accoppiamento con AA:BB:CC:A4:AA:CD
[CHG] Dispositivo AA:BB:CC:A4:AA:CD Connesso: sì
[My Bluetooth Speaker]# [CHG] Dispositivo AA:BB:CC:A4:AA:CD UUIDs: 0000110b-0000-1000-8000-00xxxxxxxxxx
[CHG] Dispositivo AA:BB:CC:A4:AA:CD UUIDs: 0000110c-0000-1000-8000-00xxxxxxxxxx
[CHG] Dispositivo AA:BB:CC:A4:AA:CD UUIDs: 0000110e-0000-1000-8000-00xxxxxxxxxx
[CHG] Dispositivo AA:BB:CC:A4:AA:CD Accoppiato: sì
Accoppiamento riuscito
[CHG] Dispositivo AA:BB:CC:A4:AA:CD Connesso: no
[bluetooth]# 
[bluetooth]# trust AA:BB:CC:A4:AA:CD
[bluetooth]# [CHG] Dispositivo AA:BB:CC:A4:AA:CD Affidabile: sì
Modifica dell'affidabilità di AA:BB:CC:A4:AA:CD riuscita
[bluetooth]# 
[bluetooth]# connect AA:BB:CC:A4:AA:CD
Tentativo di connessione a AA:BB:CC:A4:AA:CD
[bluetooth]# [CHG] Dispositivo AA:BB:CC:A4:AA:CD RSSI: -63
[CHG] Dispositivo AA:BB:CC:A4:AA:CD Connesso: sì
Connessione riuscita
[My Bluetooth Speaker]# scan off
[CHG] Dispositivo AA:BB:CC:A4:AA:CD RSSI è nullo
Rilevamento interrotto
[CHG] Controller 00:11:22:33:95:7F Rilevamento: no

Congratulazioni, ora puoi connetterti automaticamente al tuo altoparlante Bluetooth!

Ora è il momento di configurare ALSA per utilizzare il modulo Bluetooth bluealsa, in modo da poter definire un dispositivo pcm ALSA corrispondente al tuo altoparlante Bluetooth. Per un server headless che utilizza bluealsa con un dispositivo Bluetooth fisso è probabilmente più semplice che configurare Pulseaudio e il suo comportamento di commutazione del flusso. Configureremo ALSA creando una alsa-configuration personalizzata per il alsa-service-type. La configurazione dichiarerà un tipo pcm bluealsa dal modulo bluealsa fornito dal pacchetto bluez-alsa, e quindi definirà un dispositivo pcm di quel tipo per il tuo altoparlante Bluetooth.

Tutto ciò che resta da fare è far sì che MPD invii dati audio a questo dispositivo ALSA. Aggiungiamo anche un’uscita MPD secondaria che rende i file audio attualmente riprodotti disponibili come stream tramite un server web sulla porta 8080. Quando abilitato un dispositivo sulla rete potrebbe ascoltare il flusso audio collegando qualsiasi lettore multimediale compatibile al server HTTP sulla porta 8080, indipendentemente dallo stato dell’altoparlante Bluetooth.

Quello che segue è lo schema di una dichiarazione operating-system che dovrebbe compiere i compiti sopra menzionati:

(use-modules (gnu))
(use-service-modules audio dbus sound #;... etc)
(use-package-modules audio linux #;... etc)
(operating-system
 ;; ...
 (packages (cons* bluez bluez-alsa
 %base-packages))
 (services
 ;; ...
 (service mpd-service-type
 (mpd-configuration
 (user "il-tuo-nome-utente")
 (music-dir "/percorso/alla/tua/musica")
 (address "192.168.178.20")
 (outputs (list (mpd-output
 (type "alsa")
 (name "MPD")
 (extra-options
 ;; Usa lo stesso nome della configurazione ALSA
 ;; qui sotto.
 '((device . "pcm.btspeaker"))))
 (mpd-output
 (type "httpd")
 (name "streaming")
 (enabled? #false)
 (always-on? #true)
 (tags? #true)
 (mixer-type 'null)
 (extra-options
 '((encoder . "vorbis")
 (port . "8080")
 (bind-to-address . "192.168.178.20")
 (max-clients . "0") ;nessun limite
 (quality . "5.0")
 (format . "44100:16:1"))))))))
 (dbus-service #:services (list bluez-alsa))
 (bluetooth-service #:auto-enable? #t)
 (service alsa-service-type
 (alsa-configuration
 (pulseaudio? #false) ;non ne abbiamo bisogno
 (extra-options
 #~(string-append "\
# Dichiara il tipo di dispositivo audio Bluetooth \"bluealsa\" dal modulo bluealsa
pcm_type.bluealsa {
 lib \""
#$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_pcm_bluealsa.so") "\"
}
# Dichiara il tipo di dispositivo di controllo \"bluealsa\" dallo stesso modulo
ctl_type.bluealsa {
 lib \""
#$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_ctl_bluealsa.so") "\"
}
# Definisci il dispositivo audio Bluetooth effettivo.
pcm.btspeaker {
 type bluealsa
 device \"AA:BB:CC:A4:AA:CD\" # identificatore unico del dispositivo
 profile \"a2dp\"
}
# Definisci un controller associato.
ctl.btspeaker {
 type bluealsa
}
"))))))

Goditi la musica con il client MPD di tua scelta o un lettore multimediale capace di streaming via HTTP!


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

4 Contenitori

Il kernel Linux fornisce una serie di strutture condivise che sono disponibili ai processi nel sistema. Queste strutture includono una vista condivisa sul file system, altri processi, dispositivi di rete, identità di utenti e gruppi, e alcune altre. Dal kernel Linux 3.19 un utente può scegliere di unshare alcune di queste strutture condivise per processi selezionati, fornendo loro (e ai loro processi figli) una vista diversa del sistema.

Un processo con un namespace mount non condiviso, ad esempio, ha la sua propria vista sul file system — sarà in grado di vedere solo le directory che sono state esplicitamente vincolate nel suo namespace mount. Un processo con il suo proprio namespace proc si considererà l’unico processo in esecuzione sul sistema, in esecuzione come PID 1.

Guix utilizza queste funzionalità del kernel per fornire ambienti completamente isolati e anche contenitori Guix System completi, macchine virtuali leggere che condividono il kernel del sistema host. Questa funzionalità è particolarmente utile quando si utilizza Guix su una distribuzione esterna per prevenire interferenze da librerie o file di configurazione esterni disponibili a livello di sistema.


Successivo: , Su: Contenitori [Contenuti][Indice]

4.1 Contenitori Guix

Il modo più semplice per iniziare è usare guix shell con l’opzione --container. Vedi Invocare guix shell in Manuale di riferimento di GNU Guix per un riferimento delle opzioni valide.

Il seguente frammento avvia un processo shell minimale con la maggior parte dei namespace non condivisi dal sistema. La directory di lavoro corrente è visibile al processo, ma qualsiasi altra cosa sul file system non è disponibile. Questa estrema isolazione può essere molto utile quando si desidera escludere qualsiasi tipo di interferenza da variabili d’ambiente, librerie installate globalmente o file di configurazione.

guix shell --container

È un ambiente desolato, sterile, deserto. Scoprirai che nemmeno i coreutils GNU sono disponibili qui, quindi per esplorare questa landa deserta devi usare i comandi shell integrati. Anche la di solito gigantesca directory /gnu/store è ridotta a una flebile ombra di se stessa.

$ echo /gnu/store/*
/gnu/store/…-gcc-10.3.0-lib
/gnu/store/…-glibc-2.33
/gnu/store/…-bash-static-5.1.8
/gnu/store/…-ncurses-6.2.20210619
/gnu/store/…-bash-5.1.8
/gnu/store/…-profile
/gnu/store/…-readline-8.1.1

Non c’è molto che tu possa fare in un ambiente come questo oltre a uscirne. Puoi usare ^D o exit per terminare questo ambiente shell limitato.

È possibile rendere disponibili altre directory all’interno dell’ambiente del contenitore; utilizzare --expose=DIRECTORY per montare con bind la directory specificata come posizione di sola lettura all’interno del contenitore, o utilizzare --share=DIRECTORY per rendere la posizione scrivibile. Con un argomento di mappatura aggiuntivo dopo il nome della directory è possibile controllare il nome della directory all’interno del contenitore. Nell’esempio seguente mappiamo /etc sul sistema host a /the/host/etc all’interno di un contenitore in cui sono installati i coreutils GNU.

$ guix shell --container --share=/etc=/the/host/etc coreutils
$ ls /the/host/etc

Allo stesso modo, puoi impedire che la directory di lavoro corrente venga mappata nel contenitore con l’opzione --no-cwd. Un’altra buona idea è creare una directory dedicata che fungerà da directory home del contenitore, e avviare la shell del contenitore da quella directory.

Su un sistema esterno, un ambiente container può essere utilizzato per compilare software che non può essere collegato a librerie di sistema o alla toolchain del compilatore del sistema. Un caso d’uso comune in un contesto di ricerca è l’installazione di pacchetti da una sessione R. Al di fuori di un ambiente container è molto probabile che la toolchain del compilatore esterno e le librerie di sistema incompatibili vengano trovate per prime, risultando in binari incompatibili che non possono essere utilizzati da R. In una shell container questo problema scompare, poiché le librerie di sistema e gli eseguibili semplicemente non sono disponibili a causa del namespace mount non condiviso.

Prendiamo un manifesto completo che fornisce un ambiente di sviluppo confortevole per l’uso con R:

(specifications->manifest
 (list "r-minimal"
 ;; pacchetti base
 "bash-minimal"
 "glibc-locales"
 "nss-certs"
 ;; Strumenti comuni da riga di comando per evitare che il contenitore sia troppo vuoto.
 "coreutils"
 "grep"
 "which"
 "wget"
 "sed"
 ;; Strumenti R markdown
 "pandoc"
 ;; Toolchain e librerie comuni per "install.packages"
 "gcc-toolchain@10"
 "gfortran-toolchain"
 "gawk"
 "tar"
 "gzip"
 "unzip"
 "make"
 "cmake"
 "pkg-config"
 "cairo"
 "libxt"
 "openssl"
 "curl"
 "zlib"))

Utilizziamolo per eseguire R all’interno di un ambiente container. Per comodità, condividiamo il namespace net per utilizzare le interfacce di rete del sistema host. Ora possiamo compilare i pacchetti R dal sorgente nel modo tradizionale senza doverci preoccupare di disallineamenti ABI o incompatibilità.

$ guix shell --container --network --manifest=manifest.scm -- R
R version 4.2.1 (2022年06月23日) -- "Funny-Looking Kid"
Copyright (C) 2022 The R Foundation for Statistical Computing
…
> e <- Sys.getenv("GUIX_ENVIRONMENT")
> Sys.setenv(GIT_SSL_CAINFO=paste0(e, "/etc/ssl/certs/ca-certificates.crt"))
> Sys.setenv(SSL_CERT_FILE=paste0(e, "/etc/ssl/certs/ca-certificates.crt"))
> Sys.setenv(SSL_CERT_DIR=paste0(e, "/etc/ssl/certs"))
> install.packages("Cairo", lib=paste0(getwd()))
…
* installing *source* package 'Cairo' ...
…
* DONE (Cairo)
I pacchetti sorgente scaricati si trovano in
	'/tmp/RtmpCuwdwM/downloaded_packages'
> library("Cairo", lib=getwd())
> # successo!

L’uso delle shell container è divertente, ma possono diventare un po’ complicate quando si vuole andare oltre un singolo processo interattivo. Alcuni compiti diventano molto più facili quando si basano sulla solida fondazione di un vero sistema Guix e del suo ricco set di servizi di sistema. La prossima sezione ti mostrerà come avviare un sistema Guix completo all’interno di un container.


Precedente: , Su: Contenitori [Contenuti][Indice]

4.2 Contenitori di Sistema Guix

Il sistema Guix fornisce una vasta gamma di servizi di sistema interconnessi che sono configurati in modo dichiarativo per formare una fondazione affidabile e senza stato per il sistema GNU per qualsiasi attività tu gli assegni. Anche quando usi Guix su una distribuzione esterna, puoi beneficiare del design del sistema Guix eseguendo un’istanza di sistema come container. Usando le stesse funzionalità del kernel di namespace non condivisi menzionati nella sezione precedente, l’istanza Guix System risultante è isolata dal sistema host e condivide solo le posizioni del file system che dichiari esplicitamente.

Un contenitore del sistema Guix differisce dal processo di shell creato da guix shell --container in una serie di modi importanti. Mentre in una shell contenitore il processo containerizzato è un processo shell Bash, un contenitore del sistema Guix esegue Shepherd come PID 1. In un contenitore di sistema tutti i servizi di sistema (vedi Services in GNU Guix Reference Manual) sono configurati esattamente come lo sarebbero su un sistema Guix in una macchina virtuale o su hardware bare metal — questo include i demoni gestiti da GNU Shepherd (vedi Servizi Shepherd in Manuale di riferimento di GNU Guix) così come altri tipi di estensioni al sistema operativo (vedi Composizione dei servizi in Manuale di riferimento di GNU Guix).

Il percepito aumento di complessità nell’esecuzione di un contenitore del sistema Guix è facilmente giustificato quando si ha a che fare con applicazioni più complesse che hanno requisiti più elevati o semplicemente più rigidi sui loro contesti di esecuzione — file di configurazione, account utente dedicati, directory per cache o file di log, ecc. Nel sistema Guix le esigenze di questo tipo di software sono soddisfatte attraverso l’implementazione di servizi di sistema.


4.2.1 Un contenitore Database

Un buon esempio potrebbe essere un server di database PostgreSQL. Gran parte della complessità della configurazione di un tale server di database è incapsulata in questa ingannevolmente breve dichiarazione di servizio:

Una dichiarazione completa del sistema operativo da utilizzare con un contenitore del sistema Guix sarebbe simile a questa:

(use-modules (gnu))
(use-package-modules databases)
(use-service-modules databases)
(operating-system
 (host-name "container")
 (timezone "Europe/Berlin")
 (file-systems (cons (file-system
 (device (file-system-label "non-importa"))
 (mount-point "/")
 (type "ext4"))
 %base-file-systems ))
 (bootloader (bootloader-configuration
 (bootloader grub-bootloader)
 (targets '("/dev/sdX"))))
 (services
 (cons* (service postgresql-service-type
 (postgresql-configuration
 (postgresql postgresql-14)
 (config-file
 (postgresql-config-file
 (log-destination "stderr")
 (hba-file
 (plain-file "pg_hba.conf"
 "\
local	all	all			trust
host	all	all	10.0.0.1/32 	trust"))
 (extra-config
 '(("listen_addresses" "*")
 ("log_directory" "/var/log/postgresql")))))))
 (service postgresql-role-service-type
 (postgresql-role-configuration
 (roles
 (list (postgresql-role
 (name "test")
 (create-database? #t))))))
 %base-services )))

Con postgresql-role-service-type definiamo un ruolo “test” e creiamo un database corrispondente, in modo da poter testare subito senza alcuna ulteriore configurazione manuale. Le impostazioni di postgresql-config-file permettono a un client dall’indirizzo IP 10.0.0.1 di connettersi senza richiedere autenticazione—una cattiva idea nei sistemi di produzione, ma comoda per questo esempio.

Costruiamo uno script che avvierà un’istanza di questo sistema Guix come contenitore. Scrivi la dichiarazione operating-system sopra in un file os.scm e poi usa guix system container per costruire il launcher. (vedi Invocare guix system in Manuale di riferimento di GNU Guix).

$ guix system container os.scm
Verranno costruite le seguenti derivazioni:
 /gnu/store/…-run-container.drv
 …
costruzione di /gnu/store/…-run-container.drv...
/gnu/store/…-run-container

Ora che abbiamo uno script di avvio, possiamo eseguirlo per avviare il nuovo sistema con un servizio PostgreSQL in esecuzione. Si noti che a causa di alcune limitazioni non ancora risolte, dobbiamo eseguire il launcher come utente root, ad esempio con sudo.

$ sudo /gnu/store/…-run-container
il contenitore di sistema è in esecuzione come PID 5983
…

Metti in background il processo con Ctrl-z seguito da bg. Nota il ID del processo nell’output; ci servirà per connetterci al contenitore più tardi. Sai cosa? Proviamo a connetterci al contenitore subito. Useremo nsenter, uno strumento fornito dal pacchetto util-linux:

$ guix shell util-linux
$ sudo nsenter -a -t 5983
root@container /# pgrep -a postgres
49 /gnu/store/…-postgresql-14.4/bin/postgres -D /var/lib/postgresql/data --config-file=/gnu/store/…-postgresql.conf -p 5432
51 postgres: checkpointer
52 postgres: background writer
53 postgres: walwriter
54 postgres: autovacuum launcher
55 postgres: stats collector
56 postgres: logical replication launcher
root@container /# exit

Il servizio PostgreSQL è in esecuzione nel contenitore!


4.2.2 Networking dei contenitori

A che serve un sistema Guix che esegue un servizio di database PostgreSQL come contenitore quando possiamo comunicare con esso solo con processi originari del contenitore? Sarebbe molto meglio se potessimo comunicare con il database tramite la rete.

Il modo più semplice per farlo è creare una coppia di dispositivi Ethernet virtuali connessi (noti come veth). Spostiamo uno dei dispositivi (ceth-test) nel namespace net del contenitore e lasciamo l’altra estremità (veth-test) della connessione sul sistema host.

pid=5983
ns="guix-test"
host="veth-test"
client="ceth-test"
# Collega il nuovo net namespace "guix-test" al PID del contenitore.
sudo ip netns attach $ns $pid
# Crea la coppia di dispositivi
sudo ip link add $host type veth peer name $client
# Sposta il dispositivo client nel namespace di rete del contenitore
sudo ip link set $client netns $ns

Quindi configuriamo il lato host:

sudo ip link set $host up
sudo ip addr add 10.0.0.1/24 dev $host

…e poi configuriamo il lato client:

sudo ip netns exec $ns ip link set lo up
sudo ip netns exec $ns ip link set $client up
sudo ip netns exec $ns ip addr add 10.0.0.2/24 dev $client

A questo punto l’host può raggiungere il contenitore all’indirizzo IP 10.0.0.2, e il contenitore può raggiungere l’host all’IP 10.0.0.1. Questo è tutto ciò di cui abbiamo bisogno per parlare con il server di database all’interno del contenitore dal sistema host all’esterno.

$ psql -h 10.0.0.2 -U test
psql (14.4)
Digita "help" per aiuto.
test=> CREATE TABLE hello (who TEXT NOT NULL);
CREATE TABLE
test=> INSERT INTO hello (who) VALUES ('world');
INSERT 0 1
test=> SELECT * FROM hello;
 who
-------
 world
(1 riga)

Ora che abbiamo finito con questa piccola dimostrazione, puliamo:

sudo kill $pid
sudo ip netns del $ns
sudo ip link del $host

Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

5 Macchine virtuali

Guix può produrre immagini disco (vedi Invocare guix system in Manuale di riferimento di GNU Guix) che possono essere utilizzate con soluzioni di macchine virtuali come virt-manager, GNOME Boxes o il più semplice QEMU, tra gli altri.

Questo capitolo si propone di fornire esempi pratici e concreti relativi all’utilizzo e alla configurazione di macchine virtuali su un sistema Guix.


Successivo: , Su: Macchine virtuali [Contenuti][Indice]

5.1 Ponte di rete per QEMU

Per impostazione predefinita, QEMU utilizza un back-end di rete host cosiddetto “user mode”, che è comodo in quanto non richiede alcuna configurazione. Sfortunatamente, è anche piuttosto limitato. In questa modalità, la VM (macchina virtuale) guest può accedere alla rete nello stesso modo in cui lo farebbe l’host, ma non può essere raggiunta dall’host. Inoltre, poiché la modalità di rete utente di QEMU si basa su ICMP, gli strumenti di rete basati su ICMP come ping not funzionano in questa modalità. Pertanto, è spesso desiderabile configurare un bridge di rete, che consente al guest di partecipare pienamente alla rete. Ciò è necessario, ad esempio, quando il guest deve essere utilizzato come server.

5.1.1 Creazione di un’interfaccia bridge di rete

Esistono molti modi per creare un bridge di rete. Il seguente comando mostra come usare NetworkManager e il suo strumento nmcli da riga di comando (CLI), che dovrebbe essere già disponibile se la dichiarazione del tuo sistema operativo si basa su uno dei modelli desktop:

# nmcli con add type bridge con-name br0 ifname br0

Per far sì che questo bridge faccia parte della tua rete, devi associare il tuo bridge di rete all’interfaccia Ethernet usata per connetterti alla rete. Supponendo che la tua interfaccia si chiami ‘enp2s0’, il seguente comando può essere usato per farlo:

# nmcli con add type bridge-slave ifname enp2s0 master br0

Importante: Solo le interfacce Ethernet possono essere aggiunte a un bridge. Per le interfacce wireless, considerare l’approccio di rete instradata dettagliato in Vedi Rete instradata per libvirt.

Per impostazione predefinita, il bridge di rete consentirà ai tuoi ospiti di ottenere il loro indirizzo IP tramite DHCP, se disponibile sulla tua rete locale. Per semplicità, questo è ciò che useremo qui. Per trovare facilmente gli ospiti, possono essere configurati per pubblicizzare i loro nomi host tramite mDNS.

5.1.2 Configurazione dello script helper del bridge QEMU

QEMU viene fornito con un programma di aiuto per utilizzare comodamente un’interfaccia bridge di rete come utente non privilegiato vedi Network options in Documentazione QEMU. Il binario deve essere reso setuid root per il corretto funzionamento; questo può essere ottenuto aggiungendolo al campo privileged-programs della tua definizione operating-system (host), come mostrato sotto:

(privileged-programs
 (cons (privileged-program
 (program (file-append qemu "/libexec/qemu-bridge-helper"))
 (setuid? #t))
 %default-privileged-programs))

Il file /etc/qemu/bridge.conf deve anche essere modificato per consentire l’interfaccia del bridge, poiché l’impostazione predefinita è di negare tutto. Aggiungi quanto segue all’elenco dei servizi per farlo:

(extra-special-file "/etc/qemu/host.conf"
 (plain-file "host.conf" "allow br0\n"))

5.1.3 Avviare QEMU con le opzioni da riga di comando corrette

Quando si invoca QEMU, le seguenti opzioni devono essere fornite in modo che il bridge di rete sia utilizzato, dopo aver selezionato un indirizzo MAC unico per il guest.

Importante: Per impostazione predefinita, viene utilizzato un singolo indirizzo MAC per tutti gli ospiti, a meno che non venga fornito. Il mancato fornitura di indirizzi MAC diversi a ciascuna macchina virtuale che utilizza il bridge causerebbe problemi di rete.

$ qemu-system-x86_64 [...] \
 -device virtio-net-pci,netdev=user0,mac=XX:XX:XX:XX:XX:XX \
 -netdev bridge,id=user0,br=br0 \
 [...]

Per generare indirizzi MAC che hanno il prefisso registrato da QEMU, può essere utilizzato il seguente frammento:

mac_address="52:54:00:$(dd if=/dev/urandom bs=512 count=1 2>/dev/null \
 | md5sum \
 | sed -E 's/^(..)(..)(..).*$/1円:2円:3円/')"
echo $mac_address

5.1.4 Problemi di rete causati da Docker

Se usi Docker sulla tua macchina, potresti riscontrare problemi di connettività quando tenti di usare un bridge di rete, causati dal fatto che Docker si basa anche sui bridge di rete e configura le proprie regole di routing. La soluzione è aggiungere il seguente frammento iptables alla tua dichiarazione operating-system:

(service iptables-service-type
 (iptables-configuration
 (ipv4-rules (plain-file "iptables.rules" "\
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A FORWARD -i br0 -o br0 -j ACCEPT
COMMIT
"))

Successivo: , Precedente: , Su: Macchine virtuali [Contenuti][Indice]

5.2 Rete instradata per libvirt

Se la macchina che ospita le tue macchine virtuali è collegata in modalità wireless alla rete, non sarai in grado di usare un vero bridge di rete come spiegato nella sezione precedente (vedi Ponte di rete per QEMU). In questo caso, la prossima migliore opzione è usare uno switch di rete virtuale con routing statico e configurare una macchina virtuale basata su libvirt per usarlo (tramite la GUI di virt-manager per esempio). Questo è simile alla modalità di funzionamento predefinita di QEMU/libvirt, tranne che invece di usare NAT (Network Address Translation), si basa su rotte statiche per unire l’indirizzo IP della VM (macchina virtuale) alla LAN (rete locale). Questo fornisce connettività bidirezionale da e verso la macchina virtuale, che è necessaria per esporre i servizi ospitati sulla macchina virtuale.

5.2.1 Creazione di uno switch di rete virtuale

Uno switch di rete virtuale consiste in un dispositivo di rete virtuale chiamato ‘bridge virtuale’, server DHCP (dnsmasq) e regole firewall (iptables). Vedi l’articolo wiki di libvirt sulle Reti Virtuali per maggiori dettagli sulle modalità di funzionamento, gestione e implementazione degli switch di rete virtuali.

Il comando virsh, fornito dal pacchetto libvirt, rende molto facile creare uno switch virtuale. Per prima cosa devi scegliere una sottorete di rete per il tuo switch virtuale; se la tua LAN domestica è nella rete ‘192.168.1.0/24’, potresti optare per l’uso ad es.: ‘192.168.2.0/24’. Definisci un file XML, ad es.: /tmp/virbr0.xml, contenente quanto segue:

<network>
 <name>virbr0</name>
 <bridge name="virbr0" />
 <forward mode="route"/>
 <ip address="192.168.2.0" netmask="255.255.255.0">
 <dhcp>
 <range start="192.168.2.1" end="192.168.2.254"/>
 </dhcp>
 </ip>
</network>

Quindi crea e configura l’interfaccia usando il comando virsh, come root:

virsh net-define /tmp/virbr0.xml
virsh net-autostart virbr0
virsh net-start virbr0

L’interfaccia ‘virbr0’ dovrebbe ora essere visibile ad es.: tramite il comando ‘ip address’. Verrà avviata automaticamente ogni volta che la tua macchina virtuale libvirt viene avviata.

5.2.2 Configurazione delle rotte statiche per il tuo bridge virtuale

Se hai configurato la tua macchina virtuale per utilizzare la tua nuova interfaccia bridge virtuale ‘virbr0’, dovrebbe già ricevere un IP tramite DHCP come ‘192.168.2.15’ ed essere raggiungibile dal server che la ospita, ad es.: tramite ‘ping 192.168.2.15’. C’è un’ultima configurazione necessaria affinché la VM possa raggiungere la rete esterna: aggiungere rotte statiche al router della rete.

In questo esempio, la rete LAN è ‘192.168.1.0/24’ e la pagina web di configurazione del router potrebbe essere accessibile ad es.: tramite la pagina http://192.168.1.1. Su un router che esegue il firmware libreCMC, dovresti navigare alla pagina Rete → Rotte Statiche (https://192.168.1.1/cgi-bin/luci/admin/network/routes), e aggiungeresti una nuova voce a ‘Rotte IPv4 Statiche’ con le seguenti informazioni:

Interfaccia

lan

Destinazione

192.168.2.0

Maschera di rete IPv4

255.255.255.0

Gateway IPv4

ip-server

Tipo di rotta

unicast

dove server-ip è l’indirizzo IP della macchina che ospita le VM, che dovrebbe essere statico.

Dopo aver salvato/applicato questa nuova rotta statica, la connettività esterna dovrebbe funzionare all’interno della tua VM; puoi ad es.: eseguire ‘ping gnu.org’ per verificare che funzioni correttamente.


Successivo: , Precedente: , Su: Macchine virtuali [Contenuti][Indice]

5.3 Rete personalizzata basata su NAT per libvirt

Come menzionato nella sezione precedente (vedi Rete instradata per libvirt), libvirt permette di definire reti virtuali tramite file XML e di gestirle con il comando virsh. I dettagli della creazione e rimozione di switch di rete virtuali sono gestiti da libvirt, quindi l’utente non deve occuparsene.

Tuttavia, la gestione degli switch di rete virtuali da parte di libvirt può a volte entrare in conflitto con configurazioni di rete più complesse. In particolare, le regole iptables inserite da libvirt per gli switch che operano in modalità NAT possono entrare in conflitto con regole iptables/nftables esistenti, portando a un filtraggio dei pacchetti insicuro o interrotto.

In questi casi, l’unica soluzione è configurare manualmente uno switch di rete virtuale. Questa sezione fornirà istruzioni su come farlo utilizzando i servizi del sistema Guix.

5.3.1 Creazione del bridge di rete virtuale

Il static-networking-service-type può essere usato per creare un bridge di rete virtuale e assegnargli un indirizzo IP:

(service static-networking-service-type
 (list (static-networking
 ;; La fornitura predefinita è 'networking; se stai usando qualsiasi
 ;; altro servizio con questa fornitura, come
 ;; `network-manager-service-type`, allora devi cambiare il
 ;; predefinito.
 (provision '(static-networking))
 (links
 (list (network-link
 (name "virbr0")
 (type 'bridge)
 (arguments '()))))
 (addresses
 (list (network-address
 (device "virbr0")
 (value "192.168.10.1/24")))))))

5.3.2 Esecuzione di dnsmasq per il bridge di rete virtuale

Il dnsmasq-service-type può essere usato per fornire DNS e DHCP per gli ospiti connessi a questo switch di rete virtuale:

(service dnsmasq-service-type
 (dnsmasq-configuration
 ;; Puoi avere più istanze di `dnsmasq-service-type` purché
 ;; ognuna abbia una diversa shepherd-provision.
 (shepherd-provision '(dnsmasq-virbr0))
 (extra-options (list
 ;; Bind solo al bridge virtuale. Questo
 ;; evita conflitti con altre istanze di
 ;; dnsmasq in esecuzione.
 "--except-interface=lo"
 "--interface=virbr0"
 "--bind-dynamic"
 ;; Indirizzi IPv4 da offrire alle VM. Questo
 ;; dovrebbe corrispondere alla sottorete scelta.
 "--dhcp-range=192.168.10.2,192.168.10.254"))))

5.3.3 Configurazione del NAT per lo switch di rete virtuale

Se intendi utilizzare lo switch di rete virtuale in modalità NAT, dovrai utilizzare le regole nftables (o iptables) per impostare il masquerading IP. Il seguente esempio mostra come utilizzare nftables-service-type per farlo:

(service nftables-service-type
 (nftables-configuration
 (ruleset
 (plain-file "nftables.conf"
 "\
table inet filter {
 input catena {
 tipo filtro hook input priorità filtro; policy drop;
 # Aggiungi qui le tue regole di filtraggio pacchetti esistenti...
 iifname virbr0 udp dport 67 contatore accetta commento \"consenti DHCP su virbr0\"
 iifname virbr0 meta l4proto {tcp, udp} th dport 53 accetta \\
 commento \"consenti DNS su virbr0\"
 }
 chain forward {
 type filter hook forward priority filter; policy drop;
 # Aggiungi qui le tue regole di inoltro esistenti...
 iifname virbr0 accept comment \"consenti il traffico in uscita da virbr0\"
 oifname virbr0 ct state {established, related } accept \\
 comment \"consenti il traffico stabilito verso virbr0\"
 }
}
table inet nat {
 chain postrouting {
 type nat hook postrouting priority srcnat; policy accept;
 # Aggiungi qui le tue regole NAT esistenti...
 iifname virbr0 ip daddr { 224.0.0.0/24, 255.255.255.255/32 } return \\
 comment \"non mascherare verso blocchi di indirizzi riservati\"
 iifname virbr0 oifname != virbr0 masquerade \\
 comment \"mascherare tutto il traffico in uscita dalle VM\"
 }
}
"))))

Assicurati di avere l’inoltro IPv4 abilitato (puoi usare sysctl-service-type per questo).


Precedente: , Su: Macchine virtuali [Contenuti][Indice]

5.4 Riferimenti

  • The (unofficial) libvirt Networking Handbook
    Nota che questa risorsa è piuttosto datata al momento della stesura (a marzo 2025, è stata aggiornata l’ultima volta nel 2015). Ciononostante, gli autori di questo capitolo l’hanno trovata una preziosa fonte di informazioni.

Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

6 Gestione avanzata dei pacchetti

Guix è un gestore di pacchetti funzionale che offre molte funzionalità oltre a ciò che i gestori di pacchetti più tradizionali possono fare. Per i non iniziati, queste funzionalità potrebbero non avere casi d’uso ovvi all’inizio. Lo scopo di questo capitolo è dimostrare alcuni concetti avanzati di gestione dei pacchetti.

vedi Gestione dei pacchetti in it, Manuale di riferimento GNU Guix per un riferimento completo.


Su: Gestione avanzata dei pacchetti [Contenuti][Indice]

6.1 Profili Guix in pratica

Guix fornisce una funzionalità molto utile che potrebbe essere piuttosto estranea ai nuovi arrivati: i profiles. Sono un modo per raggruppare le installazioni di pacchetti e tutti gli utenti sullo stesso sistema sono liberi di usare quanti profili desiderano.

Che tu sia uno sviluppatore o meno, potresti scoprire che più profili ti offrono grande potenza e flessibilità. Sebbene spostino un po’ il paradigma rispetto ai gestori di pacchetti tradizionali, sono molto comodi da usare una volta che hai capito come configurarli.

Nota: Questa sezione è una guida ragionata sull’uso di più profili. Precede guix shell e la sua cache veloce dei profili (vedi Invocare guix shell in Manuale di riferimento di GNU Guix).

In molti casi, potresti scoprire che l’utilizzo di guix shell per configurare l’ambiente di cui hai bisogno, quando ne hai bisogno, richiede meno lavoro rispetto al mantenimento di un profilo dedicato. A te la scelta!

Se hai familiarità con ‘virtualenv’ di Python, puoi pensare a un profilo come a una sorta di ‘virtualenv’ universale che può contenere qualsiasi tipo di software, non solo software Python. Inoltre, i profili sono autosufficienti: catturano tutte le dipendenze di runtime, il che garantisce che tutti i programmi all’interno di un profilo funzioneranno sempre in qualsiasi momento.

Più profili offrono molti vantaggi:

  • Pulita separazione semantica dei vari pacchetti di cui un utente ha bisogno per diversi contesti.
  • È possibile rendere disponibili più profili nell’ambiente sia all’accesso che all’interno di una shell dedicata.
  • I profili possono essere caricati su richiesta. Ad esempio, l’utente può usare più shell, ognuna delle quali esegue profili diversi.
  • Isolamento: i programmi di un profilo non utilizzeranno i programmi dell’altro, e l’utente può persino installare diverse versioni degli stessi programmi nei due profili senza conflitto.
  • Deduplicazione: i profili condividono dipendenze che risultano essere esattamente le stesse. Questo rende più profili efficienti in termini di archiviazione.
  • Riproducibile: se utilizzato con manifest dichiarativi, un profilo può essere completamente specificato dal commit Guix attivo al momento della sua configurazione. Ciò significa che lo stesso identico profilo può essere configurato ovunque e in qualsiasi momento, con le sole informazioni di commit. Consulta la sezione sui Profili riproducibili.
  • Aggiornamenti e manutenzione più semplici: più profili rendono facile avere a portata di mano gli elenchi dei pacchetti e rendono gli aggiornamenti completamente senza attriti.

Concretamente, ecco alcuni profili tipici:

  • Le dipendenze di un progetto su cui stai lavorando.
  • Le tue librerie di linguaggio di programmazione preferite.
  • Programmi specifici per laptop (come ‘powertop’) di cui non hai bisogno su un desktop.
  • TeXlive (questo può essere davvero utile quando hai bisogno di installare un solo pacchetto per un documento che hai appena ricevuto via email).
  • Giochi.

Immergiamoci nella configurazione!


6.1.1 Configurazione di base con i manifesti

Un profilo Guix può essere configurato via un manifest. Un manifest è uno snippet di codice Scheme che specifica l’insieme di pacchetti che desideri avere nel tuo profilo; assomiglia a questo:

(specifications->manifest
 '("pacchetto-1"
 ;; Versione 1.3 del pacchetto-2.
 "pacchetto-2@1.3"
 ;; L'output "lib" del pacchetto-3.
 "pacchetto-3:lib"
 ; ...
 "pacchetto-N"))

Vedi Scrivere manifesti in Manuale di riferimento GNU Guix, per maggiori informazioni sulla sintassi.

Possiamo creare una specifica di manifest per ogni profilo e installarli in questo modo:

GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
mkdir -p "$GUIX_EXTRA_PROFILES"/my-project # se non esiste ancora
guix package --manifest=/percorso/a/guix-my-project-manifest.scm \
 --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project

Qui impostiamo una variabile arbitraria ‘GUIX_EXTRA_PROFILES’ per indicare la directory dove memorizzeremo i nostri profili nel resto di questo articolo.

Posizionare tutti i tuoi profili in una singola directory, con ogni profilo che ottiene la propria sottodirectory, è un po’ più pulito. In questo modo, ogni sottodirectory conterrà tutti i symlink per un solo profilo. Inoltre, “iterare sui profili” diventa ovvio da qualsiasi linguaggio di programmazione (ad esempio: uno script di shell) semplicemente iterando sulle sottodirectory di ‘$GUIX_EXTRA_PROFILES’.

Nota che è anche possibile scorrere l’output di

guix package --list-profiles

anche se probabilmente dovrai filtrare ~/.config/guix/current.

Per abilitare tutti i profili all’accesso, aggiungi questo al tuo ~/.bash_profile (o simile):

for i in $GUIX_EXTRA_PROFILES/*; do
 profile=$i/$(basename "$i")
 if [ -f "$profile"/etc/profile ]; then
 GUIX_PROFILE="$profile"
 . "$GUIX_PROFILE"/etc/profile
 fi
 unset profile
done

Nota per gli utenti di Guix System: quanto sopra riflette come il tuo profilo predefinito ~/.guix-profile viene attivato da /etc/profile, quest’ultimo caricato da ~/.bashrc per impostazione predefinita.

Puoi ovviamente scegliere di abilitarne solo un sottoinsieme:

for i in "$GUIX_EXTRA_PROFILES"/my-project-1 "$GUIX_EXTRA_PROFILES"/my-project-2; do
 profile=$i/$(basename "$i")
 if [ -f "$profile"/etc/profile ]; then
 GUIX_PROFILE="$profile"
 . "$GUIX_PROFILE"/etc/profile
 fi
 unset profile
done

Quando un profilo è disabilitato, è semplice abilitarlo per una singola shell senza "inquinare" il resto della sessione utente:

GUIX_PROFILE="percorso/al/mio-progetto" ; . "$GUIX_PROFILE"/etc/profile

La chiave per abilitare un profilo è source il suo file ‘etc/profile’. Questo file contiene codice shell che esporta le variabili d’ambiente corrette necessarie per attivare il software contenuto nel profilo. È costruito automaticamente da Guix e destinato all’esecuzione. Contiene le stesse variabili che otterresti eseguendo:

guix package --search-paths=prefix --profile=$my_profile"

Ancora una volta, vedi Invocare guix package in Manuale di riferimento di GNU Guix per le opzioni della riga di comando.

Per aggiornare un profilo, è sufficiente installare di nuovo il manifest:

guix package -m /percorso/a/guix-my-project-manifest.scm \
 -p "$GUIX_EXTRA_PROFILES"/my-project/my-project

Per aggiornare tutti i profili, è abbastanza facile scorrerli. Ad esempio, supponendo che le specifiche del tuo manifest siano archiviate in ~/.guix-manifests/guix-$profile-manifest.scm, con ‘$profile’ che è il nome del profilo (es.: "project1"), potresti fare quanto segue in una shell Bourne:

for profile in "$GUIX_EXTRA_PROFILES"/*; do
 guix package --profile="$profile" \
 --manifest="$HOME/.guix-manifests/guix-$profile-manifest.scm"
done

Ogni profilo ha le sue generazioni:

guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --list-generations

Puoi tornare indietro a qualsiasi generazione di un dato profilo:

guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --switch-generations=17

Infine, se vuoi passare a un profilo senza ereditare dall’ambiente corrente, puoi attivarlo da una shell vuota:

env -i $(which bash) --login --noprofile --norc
. my-project/etc/profile

6.1.2 Pacchetti richiesti

L’attivazione di un profilo si riduce essenzialmente all’esportazione di una serie di variabili d’ambiente. Questo è il ruolo del file ‘etc/profile’ all’interno del profilo.

Nota: verranno impostate solo le variabili d’ambiente dei pacchetti che le consumano.

Ad esempio, ‘MANPATH’ non verrà impostato se non esiste un’applicazione che consuma le pagine man all’interno del profilo. Quindi, se hai bisogno di accedere in modo trasparente alle pagine man una volta caricato il profilo, hai due opzioni:

  • Esporta la variabile manualmente, ad esempio
    export MANPATH=/percorso/al/profilo${MANPATH:+:}$MANPATH
    
  • Oppure includi ‘man-db’ nel manifest del profilo.

Lo stesso vale per ‘INFOPATH’ (puoi installare ‘info-reader’), ‘PKG_CONFIG_PATH’ (installa ‘pkg-config’), ecc.


6.1.3 Profilo predefinito

Che dire del profilo predefinito che Guix mantiene in ~/.guix-profile?

Puoi assegnargli il ruolo che desideri. Tipicamente installeresti il manifest dei pacchetti che vuoi usare sempre.

In alternativa, potresti mantenerlo “senza manifest” per pacchetti usa-e-getta che useresti solo per un paio di giorni. In questo modo è comodo eseguire

guix install package-foo
guix upgrade package-bar

senza dover specificare il percorso di un profilo.


6.1.4 I benefici dei manifesti

I manifest ti permettono di declare l’insieme di pacchetti che vorresti avere in un profilo (vedi Scrivere manifesti in Manuale di riferimento GNU Guix). Sono un modo conveniente per tenere a portata di mano gli elenchi dei pacchetti e, ad esempio, sincronizzarli su più macchine utilizzando un sistema di controllo versione.

Una lamentela comune sui manifest è che possono essere lenti da installare quando contengono un gran numero di pacchetti. Questo è particolarmente ingombrante quando si desidera solo un aggiornamento per un pacchetto all’interno di un manifest grande.

Questo è un motivo in più per utilizzare più profili, che si rivelano perfetti per suddividere i manifest in più insiemi di pacchetti semanticamente collegati. L’utilizzo di più profili piccoli offre maggiore flessibilità e usabilità.

I manifest offrono numerosi vantaggi. In particolare, facilitano la manutenzione:

  • Quando un profilo viene configurato da un manifest, il manifest stesso è autosufficiente per mantenere un “elenco di pacchetti” e reinstallare il profilo in seguito o su un sistema diverso. Per i profili ad-hoc, dovremmo generare manualmente una specifica di manifest e mantenere le versioni dei pacchetti per i pacchetti che non utilizzano la versione predefinita.
  • guix package --upgrade tenta sempre di aggiornare i pacchetti che hanno input propagati, anche se non c’è nulla da fare. I manifest di Guix rimuovono questo problema.
  • Quando si aggiorna parzialmente un profilo, possono sorgere conflitti (a causa di dipendenze divergenti tra i pacchetti aggiornati e quelli non aggiornati) e possono essere fastidiosi da risolvere manualmente. I manifest eliminano del tutto questo problema, poiché tutti i pacchetti vengono sempre aggiornati contemporaneamente.
  • Come accennato in precedenza, i manifest consentono profili riproducibili, mentre i comandi imperativi guix install, guix upgrade, ecc. non lo fanno, poiché producono profili diversi ogni volta anche quando contengono gli stessi pacchetti. Vedi la discussione correlata sull’argomento.
  • Le specifiche dei manifest sono utilizzabili da altri comandi ‘guix’. Ad esempio, puoi eseguire guix weather -m manifest.scm per vedere quanti sostituti sono disponibili, il che può aiutarti a decidere se vuoi provare ad aggiornare oggi o aspettare un po’. Un altro esempio: puoi eseguire guix pack -m manifest.scm per creare un pacchetto contenente tutti i pacchetti nel manifest (e i loro riferimenti transitivi).
  • Infine, i manifest hanno una rappresentazione Scheme, il tipo di record ‘<manifest>’. Possono essere manipolati in Scheme e passati alle varie API di Guix.

È importante capire che, sebbene i manifest possano essere usati per dichiarare i profili, non sono strettamente equivalenti: i profili hanno l’effetto collaterale di “fissare” i pacchetti nello store, il che impedisce che vengano raccolti dalla spazzatura (vedi Invocare guix gc in Manuale di riferimento GNU Guix) e assicura che saranno ancora disponibili in qualsiasi momento in futuro. Il comando guix shell protegge anche i profili usati di recente dalla raccolta della spazzatura; i profili che non sono stati usati per un po’ possono essere comunque raccolti dalla spazzatura, insieme ai pacchetti a cui si riferiscono.

Per essere sicuri al 100% che un dato profilo non verrà mai raccolto, installare il manifest in un profilo e usare GUIX_PROFILE=/il/profilo; . "$GUIX_PROFILE"/etc/profile come spiegato sopra: questo garantisce che il nostro ambiente di hacking sarà sempre disponibile.

Avviso di sicurezza: Sebbene mantenere i vecchi profili possa essere comodo, tieni presente che i pacchetti obsoleti potrebbero non aver ricevuto le ultime correzioni di sicurezza.


6.1.5 Profili riproducibili

Per riprodurre un profilo bit per bit, abbiamo bisogno di due informazioni:

  • un manifest (vedi Scrivere manifesti in Manuale di riferimento GNU Guix);
  • una specifica di canale Guix (vedi Replicare Guix in Manuale di riferimento GNU Guix).

Infatti, i soli manifest potrebbero non essere sufficienti: diverse versioni di Guix (o diversi canali) possono produrre output diversi per un dato manifest.

È possibile generare la specifica del canale Guix con ‘guix describe --format=channels’ (vedi Invocare guix describe in Manuale di riferimento GNU Guix). Salva questo in un file, ad esempio ‘channel-specs.scm’.

Su un altro computer, è possibile utilizzare il file di specifica del canale e il manifest per riprodurre lo stesso identico profilo:

GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
GUIX_EXTRA=$HOME/.guix-extra
mkdir -p "$GUIX_EXTRA"/my-project
guix pull --channels=channel-specs.scm --profile="$GUIX_EXTRA/my-project/guix"
mkdir -p "$GUIX_EXTRA_PROFILES/my-project"
"$GUIX_EXTRA"/my-project/guix/bin/guix package \
 --manifest=/percorso/a/guix-my-project-manifest.scm \
 --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project

È sicuro eliminare il profilo del canale Guix che hai appena installato con la specifica del canale, il profilo del progetto non dipende da esso.


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

7 Sviluppo software

Guix è uno strumento utile per gli sviluppatori; guix shell, in particolare, fornisce un ambiente di sviluppo autonomo per il tuo pacchetto, indipendentemente dal linguaggio/i in cui è scritto (vedi Invocare guix shell in Manuale di riferimento GNU Guix). Per beneficiarne, devi inizialmente scrivere una definizione di pacchetto e averla in Guix stesso, o in un canale, o direttamente nell’albero sorgente del tuo progetto come file guix.scm. Quest’ultima opzione è allettante: tutto ciò che gli sviluppatori devono fare per iniziare è clonare il repository del progetto ed eseguire guix shell, senza argomenti.

Le esigenze di sviluppo vanno oltre gli ambienti di sviluppo. Come possono gli sviluppatori eseguire l’integrazione continua del loro codice negli ambienti di costruzione di Guix? Come possono consegnare il loro codice direttamente agli utenti più avventurosi? Questo capitolo descrive un insieme di file che gli sviluppatori possono aggiungere al loro repository per configurare ambienti di sviluppo basati su Guix, integrazione continua e consegna continua — tutto in una volta sola1.


Successivo: , Su: Sviluppo software [Contenuti][Indice]

7.1 Per iniziare

Come “Guixificare” un repository? Il primo passo, come abbiamo visto, sarà aggiungere un file guix.scm alla radice del repository in questione. Prenderemo Guile come esempio in questo capitolo: è scritto principalmente in Scheme e C, e ha una serie di dipendenze — una toolchain di compilazione C, librerie C, Autoconf e i suoi amici, LaTeX, e così via. Il file guix.scm risultante assomiglia alla solita definizione di pacchetto (vedi Definire i pacchetti in Manuale di riferimento GNU Guix), solo senza il pezzo define-public:

;; Il file «guix.scm» per Guile, da usare con «guix shell».

(use-modules (guix)
 (guix build-system gnu)
 ((guix licenses) #:prefix license:)
 (gnu packages autotools)
 (gnu packages base)
 (gnu packages bash)
 (gnu packages bdw-gc)
 (gnu packages compression)
 (gnu packages flex)
 (gnu packages gdb)
 (gnu packages gettext )
 (gnu packages gperf)
 (gnu packages libffi)
 (gnu packages libunistring)
 (gnu packages linux)
 (gnu packages pkg-config)
 (gnu packages readline )
 (gnu packages tex)
 (gnu packages texinfo)
 (gnu packages version-control))
(package
 (name "guile")
 (version "3.0.99-git") ;numero di versione strano
 (source #f) ;nessuna fonte
 (build-system gnu-build-system )
 (native-inputs
 (append (list autoconf
 automake
 libtool
 gnu-gettext
 flex
 texinfo
 texlive-base ;per "make pdf"
 texlive-epsf
 gperf
 git
 gdb
 strace
 readline
 lzip
 pkg-config)
 ;; Quando si esegue la compilazione incrociata, è necessaria una
 ;; versione nativa di Guile.
 (if (%current-target-system)
 (list this-package )
 '())))
 (inputs
 (list libffi bash-minimal))
 (propagated-inputs
 (list libunistring libgc))
 (native-search-paths
 (list (search-path-specification
 (variable "GUILE_LOAD_PATH")
 (files '("share/guile/site/3.0")))
 (search-path-specification
 (variable "GUILE_LOAD_COMPILED_PATH")
 (files '("lib/guile/3.0/site-ccache")))))
 (synopsis "Implementazione Scheme destinata in particolare alle estensioni")
 (description
 "Guile è il Linguaggio Intelligente Onnipresente GNU per le Estensioni,
ed è in realtà un'implementazione Scheme completa!")
 (home-page "https://www.gnu.org/software/guile/")
 (license license:lgpl3+))

Un bel po’ di codice standard, ma ora chiunque voglia mettere mano a Guile deve solo eseguire:

guix shell

Questo fornisce loro una shell contenente tutte le dipendenze di Guile: quelle elencate sopra, ma anche dipendenze implicite come la tool chain GCC, GNU Make, sed, grep e così via. Vedi Invocare guix shell in Manuale di riferimento GNU Guix, per maggiori informazioni su guix shell.

Il consiglio dello chef: Il nostro suggerimento è di creare ambienti di sviluppo come questo:

guix shell --container --link-profile

... o, in breve:

guix shell -CP

Questo fornisce una shell in un contenitore isolato, e tutte le dipendenze appaiono in $HOME/.guix-profile, che funziona bene con le cache come config.cache (vedi File Cache in Autoconf) e i nomi di file assoluti registrati nei Makefile generati e simili. Il fatto che la shell venga eseguita in un contenitore porta tranquillità: nulla, tranne la directory corrente e le dipendenze di Guile, è visibile all’interno del contenitore; nulla del sistema può interferire con il tuo sviluppo.


Successivo: , Precedente: , Su: Sviluppo software [Contenuti][Indice]

7.2 Livello 1: Costruire con Guix

Ora che abbiamo una definizione di pacchetto (vedi Per iniziare), perché non approfittarne anche per costruire Guile con Guix? Avevamo lasciato il campo source vuoto, perché guix shell si occupa solo degli inputs del nostro pacchetto — in modo da poter configurare l’ambiente di sviluppo — non del pacchetto stesso.

Per costruire il pacchetto con Guix, dovremo compilare il campo source, seguendo queste linee:

(use-modules (guix)
 (guix git-download) ;per ‘git-predicate’
 ...)
(define vcs-file?
 ;; Restituisce vero se il file dato è sotto controllo di versione.
 (or (git-predicate (current-source-directory))
 (const #t))) ;non in un checkout Git

(package
 (name "guile")
 (version "3.0.99-git") ;numero di versione strano
 (source (local-file "." "guile-checkout"
 #:recursive? #t
 #:select? vcs-file?))
 ...)

Ecco cosa abbiamo cambiato rispetto alla sezione precedente:

  1. Abbiamo aggiunto (guix git-download) al nostro set di moduli importati, in modo da poter utilizzare la sua procedura git-predicate.
  2. Abbiamo definito vcs-file? come una procedura che restituisce vero quando le viene passato un file sotto controllo di versione. Per sicurezza, aggiungiamo un caso di fallback per quando non siamo in un checkout Git: restituiamo sempre vero.
  3. Abbiamo impostato source su un local-file — una copia ricorsiva della directory corrente ("."), limitata ai file sotto controllo di versione (il pezzo #:select?).

Da qui in poi, il nostro file guix.scm serve a un secondo scopo: ci permette di costruire il software con Guix. Il punto principale della costruzione con Guix è che si tratta di una costruzione “pulita” — puoi essere sicuro che nulla dal tuo albero di lavoro o dal sistema interferisca con il risultato della costruzione — e ti permette di testare una varietà di cose. Innanzitutto, puoi fare una semplice costruzione nativa:

guix build -f guix.scm

Ma puoi anche costruire per un altro sistema (eventualmente dopo aver configurato vedi scaricamento in Manuale di riferimento GNU Guix o vedi emulazione trasparente in Manuale di riferimento GNU Guix):

guix build -f guix.scm -s aarch64-linux -s riscv64-linux

… o compilare incrociando:

guix build -f guix.scm --target=x86_64-w64-mingw32

È inoltre possibile utilizzare le trasformazioni di pacchetto per testare le varianti di pacchetto (vedi Opzioni di trasformazione dei pacchetti in Manuale di riferimento GNU Guix):

# E se costruissimo con Clang invece di GCC?
guix build -f guix.scm \
 --with-c-toolchain=guile@3.0.99-git=clang-toolchain
# E quel flag di configurazione poco testato?
guix build -f guix.scm \
 --with-configure-flag=guile@3.0.99-git=--disable-networking

Comodo!


Successivo: , Precedente: , Su: Sviluppo software [Contenuti][Indice]

7.3 Livello 2: Il Repository come Canale

Ora abbiamo un repository Git contenente (tra le altre cose) una definizione di pacchetto (vedi Livello 1: Costruire con Guix). Non possiamo trasformarlo in un channel (vedi Canali in Manuale di riferimento GNU Guix)? Dopotutto, i canali sono progettati per spedire le definizioni dei pacchetti agli utenti, ed è esattamente quello che stiamo facendo con il nostro guix.scm.

Si scopre che possiamo effettivamente trasformarlo in un canale, ma con una cautela: dobbiamo creare una directory separata per il/i file .scm del nostro canale in modo che guix pull non carichi file .scm non correlati quando qualcuno scarica il canale — e in Guile ce ne sono molti! Quindi inizieremo così, mantenendo un symlink guix.scm di primo livello per il bene di guix shell:

mkdir -p .guix/modules
mv guix.scm .guix/modules/guile-package.scm
ln -s .guix/modules/guile-package.scm guix.scm

Per renderlo utilizzabile come parte di un canale, dobbiamo trasformare il nostro file guix.scm in un modulo pacchetto (vedi Moduli di pacchetti in Manuale di riferimento GNU Guix): lo facciamo cambiando la forma use-modules in alto in una forma define-module. Dobbiamo anche effettivamente export una variabile pacchetto, con define-public, pur restituendo il valore del pacchetto alla fine del file in modo da poter ancora usare guix shell e guix build -f guix.scm. Il risultato finale assomiglia a questo (non ripetendo cose che non sono cambiate):

(define-module (guile-package)
 #:use-module (guix)
 #:use-module (guix git-download) ;per ‘git-predicate’
 ...)
(define vcs-file?
 ;; Restituisce vero se il file dato è sotto controllo di versione.
 (or (git-predicate (dirname (dirname (current-source-directory))))
 (const #t))) ;non in un checkout Git

(define-public guile
 (package
 (name "guile")
 (version "3.0.99-git") ;numero di versione strano
 (source (local-file "../.." "guile-checkout"
 #:recursive? #t
 #:select? vcs-file?))
 ...))
;; Restituisce l'oggetto pacchetto definito sopra alla fine del modulo.
guile

Ci serve un’ultima cosa: un file .guix-channel in modo che Guix sappia dove cercare i moduli dei pacchetti nel nostro repository:

;; Questo file ci permette di presentare questo repository come un canale Guix.

(channel
 (version 0)
 (directory ".guix/modules")) ;cerca i moduli dei pacchetti sotto .guix/modules/

Per ricapitolare, ora abbiamo questi file:

.
├── .guix-channel
├── guix.scm  .guix/modules/guile-package.scm
└── .guix
  └── modules
    └── guile-package.scm

E questo è tutto: abbiamo un canale! (Potremmo fare di meglio e supportare l’autenticazione del canale in modo che gli utenti sappiano di scaricare codice autentico. Ti risparmiamo i dettagli qui, ma vale la pena considerarlo!) Gli utenti possono scaricare da questo canale aggiungendolo a ~/.config/guix/channels.scm, secondo queste linee:

(append (list (channel
 (name 'guile)
 (url "https://git.savannah.gnu.org/git/guile.git")
 (branch "main")))
 %default-channels)

Dopo aver eseguito guix pull, possiamo vedere il nuovo pacchetto:

$ guix describe
Generazione 264 26 maggio 2023 16:00:35 (corrente)
 guile 36fd2b4
 URL repository: https://git.savannah.gnu.org/git/guile.git
 ramo: main
 commit: 36fd2b4920ae926c79b936c29e739e71a6dff2bc
 guix c5bc698
 URL repository: https://git.guix.gnu.org/guix.git
 commit: c5bc698e8922d78ed85989985cc2ceb034de2f23
$ guix package -A ^guile$
guile 3.0.99-git out,debug guile-package.scm:51:4
guile 3.0.9 out,debug gnu/packages/guile.scm:317:2
guile 2.2.7 out,debug gnu/packages/guile.scm:258:2
guile 2.2.4 out,debug gnu/packages/guile.scm:304:2
guile 2.0.14 out,debug gnu/packages/guile.scm:148:2
guile 1.8.8 out gnu/packages/guile.scm:77:2
$ guix build guile@3.0.99-git
[…]
/gnu/store/axnzbl89yz7ld78bmx72vpqp802dwsar-guile-3.0.99-git-debug
/gnu/store/r34gsij7f0glg2fbakcmmk0zn4v62s5w-guile-3.0.99-git

È così che, come sviluppatore, consegni il tuo software direttamente nelle mani degli utenti! Nessun intermediario, eppure nessuna perdita di trasparenza e tracciamento della provenienza.

Con questo in atto, diventa anche banale per chiunque creare immagini Docker, pacchetti Deb/RPM o un semplice tarball con guix pack (vedi Invocare guix pack in Manuale di riferimento GNU Guix):

# Che ne dici di un'immagine Docker del nostro snapshot Guile?
guix pack -f docker -S /bin=bin guile@3.0.99-git
# E un RPM rilocabile?
guix pack -f rpm -R -S /bin=bin guile@3.0.99-git

Successivo: , Precedente: , Su: Sviluppo software [Contenuti][Indice]

7.4 Bonus: Varianti di Pacchetto

Ora abbiamo un canale effettivo, ma contiene un solo pacchetto (vedi Livello 2: Il Repository come Canale). Già che ci siamo, possiamo definire varianti di pacchetto (vedi Definire varianti di pacchetto in Manuale di riferimento GNU Guix) nel nostro file guile-package.scm, varianti che vogliamo poter testare come sviluppatori Guile — in modo simile a quanto fatto sopra con le opzioni di trasformazione. Possiamo aggiungerle così:

;; Questo è il file «.guix/modules/guile-package.scm».

(define-module (guile-package)
 ...)
(define-public guile
 ...)
(define (package-with-configure-flags p flags)
 "Restituisce P con FLAGS come flag 'configure' aggiuntivi."
 (package/inherit p
 (arguments
 (substitute-keyword-arguments (package-arguments p)
 ((#:configure-flags original-flags #~(list ))
 #~(append #$original-flags #$flags))))))
(define-public guile-without-threads
 (package
 (inherit (package-with-configure-flags guile
 #~(list "--without-threads")))
 (name "guile-without-threads")))
(define-public guile-without-networking
 (package
 (inherit (package-with-configure-flags guile
 #~(list "--disable-networking")))
 (name "guile-without-networking")))
;; Restituisce l'oggetto pacchetto definito sopra alla fine del modulo.
guile

Possiamo costruire queste varianti come pacchetti regolari una volta che abbiamo scaricato il canale. In alternativa, da un checkout di Guile, possiamo eseguire un comando come questo dal livello superiore:

guix build -L $PWD/.guix/modules guile-without-threads

Successivo: , Precedente: , Su: Sviluppo software [Contenuti][Indice]

7.5 Livello 3: Configurazione dell’Integrazione Continua

Il canale che abbiamo definito sopra (vedi Livello 2: Il Repository come Canale) diventa ancora più interessante una volta che configuriamo l’integrazione continua (CI). Ci sono diversi modi per farlo.

Puoi utilizzare uno degli strumenti di integrazione continua più diffusi, come GitLab-CI. Per farlo, devi assicurarti di eseguire i job in un’immagine Docker o in una macchina virtuale che abbia Guix installato. Se lo facessimo nel caso di Guile, avremmo un job che esegue un comando shell come questo:

guix build -L $PWD/.guix/modules guile@3.0.99-git

Fare questo funziona alla grande e ha il vantaggio di essere facile da ottenere sulla tua piattaforma CI preferita.

Detto questo, otterrai il massimo usandoti di Cuirass, uno strumento di CI progettato e strettamente integrato con Guix. Usarlo richiede più lavoro rispetto all’utilizzo di uno strumento di CI ospitato perché devi prima configurarlo, ma quella fase di configurazione è notevolmente semplificata se usi il suo servizio Guix System (vedi Integrazione continua in Manuale di riferimento GNU Guix). Tornando al nostro esempio, diamo a Cuirass un file di specifica che assomiglia a questo:

;; File di specifica Cuirass per costruire tutti i pacchetti del canale «guile».
(list (specification
 (name "guile")
 (build '(channels guile))
 (channels
 (append (list (channel
 (name 'guile)
 (url "https://git.savannah.gnu.org/git/guile.git")
 (branch "main")))
 %default-channels))))

Differisce da ciò che faresti con altri strumenti di CI in due modi importanti:

  • Cuirass sa che sta tracciando two canali, guile e guix. Infatti, il nostro pacchetto guile dipende da molti pacchetti forniti dal canale guix — GCC, la GNU libc, libffi, e così via. Le modifiche ai pacchetti del canale guix possono potenzialmente influenzare la nostra build di guile e questo è qualcosa che vorremmo vedere il prima possibile come sviluppatori Guile.
  • I risultati della costruzione non vengono scartati: possono essere distribuiti come sostituti in modo che gli utenti del nostro canale guile ottengano in modo trasparente i binari precompilati! (vedi Sostituti in Manuale di riferimento GNU Guix, per informazioni di base sui sostituti.)

Dal punto di vista di uno sviluppatore, il risultato finale è questa pagina di stato che elenca le evaluations: ogni valutazione è una combinazione di commit dei canali guix e guile che fornisce un numero di job — un job per pacchetto definito in guile-package.scm moltiplicato per il numero di architetture di destinazione.

Per quanto riguarda i sostituti, sono gratuiti! Ad esempio, poiché il nostro jobset guile è costruito su ci.guix.gnu.org, che esegue guix publish (vedi Invocare guix publish in Manuale di riferimento GNU Guix) oltre a Cuirass, si ottengono automaticamente i sostituti per le build di guile da ci.guix.gnu.org; non è necessario alcun lavoro aggiuntivo per questo.


Successivo: , Precedente: , Su: Sviluppo software [Contenuti][Indice]

7.6 Bonus: Manifest di costruzione

La specifica Cuirass sopra è comoda: costruisce ogni pacchetto nel nostro canale, che include alcune varianti (vedi Livello 3: Configurazione dell’Integrazione Continua). Tuttavia, questo potrebbe essere insufficientemente espressivo in alcuni casi: si potrebbero volere specifici job di cross-compilazione, trasformazioni, immagini Docker, pacchetti RPM/Deb, o persino test di sistema.

Per ottenere ciò, puoi scrivere un manifest (vedi Scrivere manifesti in Manuale di riferimento GNU Guix). Quello che abbiamo per Guile ha voci per le varianti di pacchetto che abbiamo definito sopra, così come varianti aggiuntive e build incrociate:

;; Questo è «.guix/manifest.scm».

(use-modules (guix)
 (guix profiles)
 (guile-package)) ;importa il nostro modulo pacchetto

(define* (package->manifest-entry* package system
 #:key target)
 "Restituisce una voce di manifest per PACKAGE su SYSTEM, opzionalmente cross-compilato su
TARGET."
 (manifest-entry
 (inherit (package->manifest-entry package ))
 (name (string-append (package-name package ) "." system
 (if target
 (string-append "." target)
 "")))
 (item (with-parameters ((%current-system system )
 (%current-target-system target))
 package ))))
(define native-builds
 (manifest
 (append (map (lambda (system )
 (package->manifest-entry* guile system ))
 '("x86_64-linux" "i686-linux"
 "aarch64-linux" "armhf-linux"
 "powerpc64le-linux"))
 (map (lambda (guile)
 (package->manifest-entry* guile "x86_64-linux"))
 (cons (package
 (inherit (package-with-c-toolchain
 guile
 `(("clang-toolchain"
 ,(specification->package
 "clang-toolchain")))))
 (name "guile-clang"))
 (list guile-without-threads
 guile-without-networking
 guile-debug
 guile-strict-typing))))))
(define cross-builds
 (manifest
 (map (lambda (target)
 (package->manifest-entry* guile "x86_64-linux"
 #:target target))
 '("i586-pc-gnu"
 "aarch64-linux-gnu"
 "riscv64-linux-gnu"
 "i686-w64-mingw32"
 "x86_64-linux-gnu"))))
(concatenate-manifests (list native-builds cross-builds))

Non entreremo nei dettagli di questo manifest; basti dire che fornisce flessibilità aggiuntiva. Ora dobbiamo dire a Cuirass di costruire questo manifest, cosa che si fa con una specifica leggermente diversa dalla precedente:

;; File di specifica Cuirass per costruire tutti i pacchetti del canale «guile».
(list (specification
 (name "guile")
 (build '(manifest ".guix/manifest.scm"))
 (channels
 (append (list (channel
 (name 'guile)
 (url "https://git.savannah.gnu.org/git/guile.git")
 (branch "main")))
 %default-channels))))

Abbiamo cambiato la parte (build …) della specifica in '(manifest ".guix/manifest.scm") in modo che prelevasse il nostro manifest, e questo è tutto!


Precedente: , Su: Sviluppo software [Contenuti][Indice]

7.7 In conclusione

Abbiamo scelto Guile come esempio in questo capitolo e puoi vedere il risultato qui:

Al giorno d’oggi, i repository sono spesso cosparsi di file nascosti per vari strumenti: .envrc, .gitlab-ci.yml, .github/workflows, Dockerfile, .buildpacks, Aptfile, requirements.txt, e così via. Potrebbe sembrare che stiamo proponendo un mucchio di file additional, ma in realtà questi file sono sufficientemente espressivi da sostituire la maggior parte o tutti quelli elencati sopra.

Con un paio di file, otteniamo il supporto per:

  • ambienti di sviluppo (guix shell);
  • build di test pulite, incluse per varianti di pacchetti e per la cross-compilazione (guix build);
  • integrazione continua (con Cuirass o con qualche altro strumento);
  • consegna continua agli utenti (via il canale e con binari precompilati);
  • generazione di artefatti di build derivati come immagini Docker o pacchetti Deb/RPM (guix pack).

Questo è un bel set di strumenti unificato (a nostro avviso!) per il deployment riproducibile del software, e un’illustrazione di come tu, come sviluppatore, puoi trarne beneficio!


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

8 Gestione dell’ambiente

Guix fornisce numerosi strumenti per gestire l’ambiente. Questo capitolo illustra tali utilità.


Su: Gestione dell’ambiente [Contenuti][Indice]

8.1 Ambiente Guix tramite direnv

Guix fornisce un pacchetto ‘direnv’, che potrebbe estendere la shell dopo il cambio di directory. Questo strumento potrebbe essere usato per preparare un ambiente Guix puro.

L’esempio seguente fornisce una funzione di shell per il file ~/.direnvrc, che potrebbe essere utilizzata dal repository Git di Guix nel file ~/src/guix/.envrc per configurare un ambiente di build simile a quello descritto in vedi Costruire da Git in Manuale di riferimento GNU Guix.

Crea un file ~/.direnvrc con codice Bash:

# Grazie a <https://github.com/direnv/direnv/issues/73#issuecomment-152284914>
export_function()
{
 local name=1ドル
 local alias_dir=$PWD/.direnv/aliases
 mkdir -p "$alias_dir"
 PATH_add "$alias_dir"
 local target="$alias_dir/$name"
 if declare -f "$name" >/dev/null; then
 echo "#!$SHELL" > "$target"
 declare -f "$name" >> "$target" 2>/dev/null
 # Notare che aggiungiamo variabili di shell al trigger della funzione.
 echo "$name \$*" >> "$target"
 chmod +x "$target"
 fi
}
use_guix()
{
 # Imposta il token GitHub.
 export GUIX_GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
 # Disattiva 'GUIX_PACKAGE_PATH'.
 export GUIX_PACKAGE_PATH=""
 # Ricrea una radice del garbage collector.
 gcroots="$HOME/.config/guix/gcroots"
 mkdir -p "$gcroots"
 gcroot="$gcroots/guix"
 if [ -L "$gcroot" ]
 then
 rm -v "$gcroot"
 fi
 # Pacchetti vari.
 PACKAGES_MAINTENANCE=(
 direnv
 git
 git:send-email
 git-cal
 gnupg
 guile-colorized
 guile-readline
 less
 ncurses
 openssh
 xdot
 )
 # Pacchetti ambiente.
 PACKAGES=(help2man guile-sqlite3 guile-gcrypt)
 # Grazie a <https://lists.gnu.org/archive/html/guix-devel/2016-09/msg00859.html>
 eval "$(guix shell --search-paths --root="$gcroot" --pure \
 --development guix ${PACKAGES[@]} ${PACKAGES_MAINTENANCE[@]} "$@")"
 # Predefinisci i flag di configurazione.
 configure()
 {
 ./configure
 }
 export_function configure
 # Esegui make e opzionalmente costruisci qualcosa.
 build()
 {
 make -j 2
 if [ $# -gt 0 ]
 then
 ./pre-inst-env guix build "$@"
 fi
 }
 export_function build
 # Predefinisci il comando Git push.
 push()
 {
 git push --set-upstream origin
 }
 export_function push
 clear # Pulisci lo schermo.
 git-cal --author='Il tuo nome' # Mostra il calendario dei contributi.
 # Mostra l'aiuto dei comandi.
 echo "
build costruisce un pacchetto o solo un progetto se non viene fornito alcun argomento
configure esegui ./configure con parametri predefiniti
push effettua il push al repository Git upstream
"
}

Ogni progetto contenente .envrc con la stringa use guix avrà variabili d’ambiente e procedure predefinite.

Esegui direnv allow per configurare l’ambiente per la prima volta.


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

9 Using Guix for Reproducible Research

Because it supports reproducible deployment, Guix is a solid foundation for reproducible research workflows. This section is targeted at scientists; it shows how to add Guix to one’s reproducible research toolbox2.

With Guix as the basis of your computational workflow, you can get what’s in essence executable provenance meta-data: it’s like the list of package name/version pairs some provide as an appendix to their publication, except more precise and immediately deployable.

This section is a guide in just four steps on how to make your computational experiments reproducible using Guix, and how to provide that information in your research paper.


Successivo: , Su: Using Guix for Reproducible Research [Contenuti][Indice]

9.1 Step 1: Setting Up the Environment

The first step is to identify precisely what packages you need in your software environment to run your computational experiment.

Assuming you have a Python script that uses NumPy, you can start by creating an environment that contains these two packages and to run your code in that environment (vedi Invoking guix shell in GNU Guix Reference Manual):

guix shell -C python python-numpy -- python3 ./myscript.py

The -C flag here (or --container) instructs guix shell to create that environment in an isolated container with nothing but the two packages you asked for. That way, if ./myscript.py needs more than these two packages, it’ll fail to run and you’ll immediately notice. On some systems --container is not supported; in that case, you can resort to --pure instead.

Perhaps you’ll find that you also need Pandas and add it to the environment:

guix shell -C python python-numpy python-pandas -- \
 python3 ./myscript.py

If you fail to guess the name of the package (this one was easy!), try guix search.

Environments for Python, R, and similar high-level languages are relatively easy to set up. For C/C++ code, you may find need many more packages:

guix shell -C gcc-toolchain cmake coreutils grep sed make -- …

Or perhaps you’ll find that you could just as well provide a for your package—vedi Defining Packages in GNU Guix Reference Manual, to learn more on how to do that.

Eventually, you’ll have a list of packages that satisfies your needs.

What if a package is missing?: Guix and the main scientific channels provide about tens of thousands of packages. Yet, there’s always the possibility that the one package you need is missing.

In that case, you will need to provide a definition for it (vedi Defining Packages in GNU Guix Reference Manual) in a dedicated channel of yours (vedi Creating a Channel in GNU Guix Reference Manual). For software in Python, R, and other high-level languages, most of the work can usually be automated by using guix import (vedi Invoking guix import in GNU Guix Reference Manual).

Join the friendly Guix community to get help!


Successivo: , Precedente: , Su: Using Guix for Reproducible Research [Contenuti][Indice]

9.2 Step 2: Recording the Environment

Now that you have that guix shell command line with a list of packages, the best course of action is to save it in a manifest file—essentially a software bill of materials—that Guix can then ingest (vedi Writing Manifests in GNU Guix Reference Manual). The easiest way to get started is by “translating” your command line into a manifest:

guix shell python python-numpy python-pandas \
 --export-manifest > manifest.scm

Put that manifest under version control! From there anyone can redeploy the software environment described by the manifest and run code in that environment:

guix shell -C -m manifest.scm -- python3 ./myscript.py

Here’s what manifest.scm reads:

;; What follows is a "manifest" equivalent to the command line you gave.
;; You can store it in a file that you may then pass to any 'guix' command
;; that accepts a '--manifest' (or '-m') option.

(specifications->manifest
 (list "python" "python-numpy" "python-pandas"))

It’s a code snippet that lists packages. Notice that there are no version numbers! Indeed, these version numbers are specified in package definitions, located in Guix channels. To allow others to reproduce the exact same environment as the one you’re running, you need to pin Guix itself , by capturing the current Guix channel commits with guix describe (vedi Replicating Guix in GNU Guix Reference Manual):

guix describe -f channels > channels.scm

This channels.scm file is similar in spirit to “lock files” that some deployment tools employ to pin package revisions. You should also keep it under version control in your code, and possibly update it once in a while when you feel like running your code against newer versions of its dependencies. With this file, anyone, at any time and on any machine, can now reproduce the exact same environment by running:

guix time-machine -C channels.scm -- \
 shell -C -m manifest.scm -- \
 python3 ./myscript.py

In this example we rely solely on the guix channel, which provides the Python packages we need. Perhaps some of the packages you need live in other channels—maybe guix-cran if you use R, maybe guix-science. That’s fine: guix describe also captures that.

Of course do include a README file giving the exact command to run the code. Not everyone uses Guix so it can be helpful to also provide minimal non-Guix setup instructions: which package versions are used, how software is built, etc. As we have seen, such instructions would likely be inaccurate and inconvenient to follow at best. Yet, it can be a useful starting point to someone trying to recreate a similar environment using different tools. It should probably be presented as such, with the understanding that the only way to get the same environment is to use Guix.


Successivo: , Precedente: , Su: Using Guix for Reproducible Research [Contenuti][Indice]

9.3 Step 3: Ensuring Long-Term Source Code Archiving

We insisted on version control before: for the manifest.scm and channels.scm files, but of course also for your own code. Our recommendation is to have these two .scm files in the same repository as the code they’re about.

Since the goal is enabling reproducibility, source code availability is a prime concern. Source code hosting services come and go and we don’t want our code to vanish in a whim and render our published research work unverifiable. Software Heritage (SWH for short) is the solution for this: SWH archives public source code and provides unique intrinsic identifiers to refer to it—SWHIDs. Guix itself is connected to SWH to (1) ensure that the source code of its packages is archived, and (2) to fall back to downloading from the SWH archive should code vanish from its original site.

Once your own code is available in a public version-control repository, such as a Git repository on your lab’s hosting service, you can ask SWH to archive it by going to its Save Code Now interface. SWH will process the request asynchronously and eventually you’ll find your code has made it into the archive.


Precedente: , Su: Using Guix for Reproducible Research [Contenuti][Indice]

9.4 Step 4: Referencing the Software Environment

This brings us to the last step: referring to our code and software environment in our beloved paper. We already have all our code and Guix files in the same repository, which is archived on SWH. Thanks to SWH, we now have a SWHID, which uniquely identifies the relevant revision of our code.

Following SWH’s own guide, we’ll pick an swh:dir kind of identifier, which refers to the directory of the relevant revision/commit of our repository, and we’ll keep contextual info for clarity—that includes the original URL. Putting it all together, we’ll conclude our paper with a sentence along these lines:

Example: The source code used to produce this study, as well as instructions to run it in the right software environment using GNU Guix, is archived on Software Heritage as swh:1:dir:cc8919d7705fbaa31efa677ce00bef7eb374fb80;origin=https://gitlab.inria.fr/lcourtes-phd/edcc-2006-redone;visit=swh:1:snp:71a4d08ef4a2e8455b67ef0c6b82349e82870b46;anchor=swh:1:rev:36fde7e5ba289c4c3e30d9afccebbe0cfe83853a.

With this information, the reader can:

  • get the source code;
  • reproduce its software environment with guix time-machine and run the code;
  • inspect and possibly modify both the code and its environment.

Mission accomplished!


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

10 Installare Guix su un Cluster

Guix è attraente per gli scienziati e i professionisti dell’HPC (calcolo ad alte prestazioni): semplifica il deployment di stack software potenzialmente complessi e consente di farlo in modo riproducibile, permettendo di ridistribuire esattamente lo stesso software su macchine diverse e in momenti diversi.

In questo capitolo esaminiamo come un amministratore di sistema di un cluster può installare Guix per un uso a livello di sistema, in modo che possa essere utilizzato su tutti i nodi del cluster, e discutiamo i vari compromessi3

Nota: Qui si assume che il cluster stia eseguendo una distribuzione GNU/Linux diversa da Guix System e che installeremo Guix su di essa.


Successivo: , Su: Installare Guix su un Cluster [Contenuti][Indice]

10.1 Configurazione di un nodo principale

L’approccio raccomandato è quello di configurare un nodo head che esegue guix-daemon ed esporta /gnu/store tramite NFS ai nodi di calcolo.

Ricorda che guix-daemon è responsabile dell’avvio dei processi di costruzione e dei download per conto dei client (vedi Invocare guix-daemon in Manuale di riferimento GNU Guix), e più in generale dell’accesso a /gnu/store, che contiene tutti i binari dei pacchetti costruiti da tutti gli utenti (vedi Lo store in Manuale di riferimento GNU Guix). “Client” qui si riferisce a tutti i comandi Guix che gli utenti vedono, come guix install. Su un cluster, questi comandi potrebbero essere eseguiti sui nodi di calcolo e vorremo che comunicassero con l’istanza guix-daemon del nodo head.

Per iniziare, il nodo head può essere installato seguendo le solite istruzioni di installazione binaria (vedi Installazione binaria in Manuale di riferimento GNU Guix). Grazie allo script di installazione, questo dovrebbe essere rapido. Una volta completata l’installazione, dobbiamo apportare alcune modifiche.

Poiché vogliamo che guix-daemon sia raggiungibile non solo dal nodo head ma anche dai nodi di calcolo, dobbiamo fare in modo che ascolti le connessioni su TCP/IP. Per fare ciò, modificheremo il file di avvio di systemd per guix-daemon, /etc/systemd/system/guix-daemon.service, e aggiungeremo un argomento --listen alla riga ExecStart in modo che assomigli a questo:

ExecStart=/var/guix/profiles/per-user/root/current-guix/bin/guix-daemon --build-users-group=guixbuild --listen=/var/guix/daemon-socket/socket --listen=0.0.0.0

Affinché queste modifiche abbiano effetto, il servizio deve essere riavviato:

systemctl daemon-reload
systemctl restart guix-daemon

Nota: Il bit --listen=0.0.0.0 significa che guix-daemon elaborerà all le connessioni TCP in entrata sulla porta 44146 (vedi Invocare guix-daemon in Manuale di riferimento GNU Guix). Questo di solito va bene in una configurazione cluster in cui il nodo head è raggiungibile esclusivamente dalla rete locale del cluster — non vuoi che sia esposto a Internet!

Il passo successivo è definire le nostre esportazioni NFS in /etc/exports aggiungendo qualcosa del genere:

/gnu/store *(ro)
/var/guix *(rw, async)
/var/log/guix *(ro)

La directory /gnu/store può essere esportata in sola lettura poiché solo guix-daemon sul nodo master la modificherà. /var/guix contiene profili utente gestiti da guix package; quindi, per consentire agli utenti di installare pacchetti con guix package, questo deve essere in lettura-scrittura.

Gli utenti possono creare tutti i profili che desiderano oltre al profilo predefinito, ~/.guix-profile. Ad esempio, guix package -p ~/dev/python-dev -i python installa Python in un profilo raggiungibile dal symlink ~/dev/python-dev. Per assicurarsi che questo profilo sia protetto dalla raccolta della spazzatura — cioè, che Python non venga rimosso da /gnu/store finché questo profilo esiste —, le directory home dovrebbero essere montate anche sul nodo head in modo che guix-daemon sia a conoscenza di questi profili non standard ed eviti di raccogliere il software a cui si riferiscono.

Potrebbe essere una buona idea rimuovere periodicamente i bit inutilizzati da /gnu/store eseguendo guix gc (vedi Invocare guix gc in Manuale di riferimento GNU Guix). Questo può essere fatto aggiungendo una voce crontab sul nodo head:

root@master# crontab -e

... con qualcosa del genere:

# Ogni giorno alle 5 del mattino, esegui il garbage collector per assicurarti
# che ci siano almeno 10 GB liberi su /gnu/store.
0 5 * * 1 /usr/local/bin/guix gc -F10G

Abbiamo finito con il nodo head! Ora passiamo ai nodi di calcolo.


Successivo: , Precedente: , Su: Installare Guix su un Cluster [Contenuti][Indice]

10.2 Configurazione dei nodi di calcolo

Innanzitutto, abbiamo bisogno che i nodi di calcolo montino le directory NFS che il nodo head esporta. Questo può essere fatto aggiungendo le seguenti righe a /etc/fstab:

head-node:/gnu/store /gnu/store nfs defaults,_netdev,vers=3 0 0
head-node:/var/guix /var/guix nfs defaults,_netdev,vers=3 0 0
head-node:/var/log/guix /var/log/guix nfs defaults,_netdev,vers=3 0 0

... dove head-node è il nome o l’indirizzo IP del tuo nodo head. Da lì in poi, supponendo che i punti di montaggio esistano, dovresti essere in grado di montare ognuno di questi sui nodi di calcolo.

Successivamente, dobbiamo fornire un comando guix predefinito che gli utenti possano eseguire quando si connettono per la prima volta al cluster (alla fine invocheranno guix pull, che fornirà loro il loro “proprio” comando guix). Simile a quanto fatto dallo script di installazione binaria sul nodo head, lo memorizzeremo in /usr/local/bin:

mkdir -p /usr/local/bin
ln -s /var/guix/profiles/per-user/root/current-guix/bin/guix \
 /usr/local/bin/guix

Dobbiamo quindi dire a guix di comunicare con il demone in esecuzione sul nostro nodo master, aggiungendo queste righe a /etc/profile:

GUIX_DAEMON_SOCKET="guix://head-node"
export GUIX_DAEMON_SOCKET

Per evitare avvisi e assicurarsi che guix utilizzi la locale corretta, dobbiamo dirgli di usare i dati di locale forniti da Guix (vedi Configurazione dell'applicazione in Manuale di riferimento GNU Guix):

GUIX_LOCPATH=/var/guix/profiles/per-user/root/guix-profile/lib/locale
export GUIX_LOCPATH
# Qui dobbiamo usare un nome di locale valido. Prova "ls $GUIX_LOCPATH/*"
# per vedere quali nomi possono essere usati.
LC_ALL=fr_FR.utf8
export LC_ALL

Per comodità, guix package genera automaticamente ~/.guix-profile/etc/profile, che definisce tutte le variabili d’ambiente necessarie per utilizzare i pacchetti — PATH, C_INCLUDE_PATH, PYTHONPATH, ecc. Allo stesso modo, guix pull lo fa sotto ~/.config/guix/current. Quindi è una buona idea caricare entrambi da /etc/profile:

for GUIX_PROFILE in "$HOME/.config/guix/current" "$HOME/.guix-profile"
do
 if [ -f "$GUIX_PROFILE/etc/profile" ]; then
 . "$GUIX_PROFILE/etc/profile"
 fi
done

Infine, Guix fornisce il completamento della riga di comando, in particolare per Bash e zsh. In /etc/bashrc, considera di aggiungere questa riga:

. /var/guix/profiles/per-user/root/current-guix/etc/bash_completion.d/guix

Ecco fatto!

Puoi verificare che tutto sia a posto accedendo a un nodo di calcolo ed eseguendo:

guix install hello

Il demone sul nodo principale dovrebbe scaricare i binari precompilati per tuo conto e decomprimerli in /gnu/store, e guix install dovrebbe creare ~/.guix-profile contenente il comando ~/.guix-profile/bin/hello.


Successivo: , Precedente: , Su: Installare Guix su un Cluster [Contenuti][Indice]

10.3 Accesso alla Rete

Guix richiede l’accesso alla rete per scaricare il codice sorgente e i binari precompilati. La buona notizia è che solo il nodo principale ne ha bisogno, poiché i nodi di calcolo si limitano a delegare a esso.

È consuetudine che i nodi del cluster abbiano accesso, nella migliore delle ipotesi, a una white list di host. Il nostro nodo principale ha bisogno almeno di ci.guix.gnu.org in questa white list, poiché è da qui che ottiene i binari precompilati per impostazione predefinita, per tutti i pacchetti presenti in Guix.

Per inciso, ci.guix.gnu.org funge anche da mirror con indirizzamento per contenuto del codice sorgente di tali pacchetti. Di conseguenza, è sufficiente avere only ci.guix.gnu.org in quella white list.

I pacchetti software mantenuti in un repository separato, come uno dei vari canali HPC, non sono disponibili da ci.guix.gnu.org. Per questi pacchetti, potresti voler estendere la white list in modo che il sorgente e i binari precompilati (supponendo che i server di terze parti forniscano binari per questi pacchetti) possano essere scaricati. Come ultima risorsa, gli utenti possono sempre scaricare il sorgente sulla propria workstation e aggiungerlo a /gnu/store del cluster, in questo modo:

GUIX_DAEMON_SOCKET=ssh://compute-node.example.org \
 guix download http://starpu.gforge.inria.fr/files/starpu-1.2.3/starpu-1.2.3.tar.gz

Il comando sopra scarica starpu-1.2.3.tar.gz and lo invia all’istanza guix-daemon del cluster tramite SSH.

I cluster isolati richiedono più lavoro. Al momento, il nostro suggerimento sarebbe quello di scaricare tutto il codice sorgente necessario su una workstation che esegue Guix. Ad esempio, usando l’opzione --sources di guix build (vedi Invocare guix build in Manuale di riferimento di GNU Guix), l’esempio seguente scarica tutto il codice sorgente da cui dipende il pacchetto openmpi:

$ guix build --sources=transitive openmpi
…
/gnu/store/xc17sm60fb8nxadc4qy0c7rqph499z8s-openmpi-1.10.7.tar.bz2
/gnu/store/s67jx92lpipy2nfj5cz818xv430n4b7w-gcc-5.4.0.tar.xz
/gnu/store/npw9qh8a46lrxiwh9xwk0wpi3jlzmjnh-gmp-6.0.0a.tar.xz
/gnu/store/hcz0f4wkdbsvsdky3c0vdvcawhdkyldb-mpfr-3.1.5.tar.xz
/gnu/store/y9akh452n3p4w2v631nj0injx7y0d68x-mpc-1.0.3.tar.gz
/gnu/store/6g5c35q8avfnzs3v14dzl54cmrvddjm2-glibc-2.25.tar.xz
/gnu/store/p9k48dk3dvvk7gads7fk30xc2pxsd66z-hwloc-1.11.8.tar.bz2
/gnu/store/cry9lqidwfrfmgl0x389cs3syr15p13q-gcc-5.4.0.tar.xz
/gnu/store/7ak0v3rzpqm2c5q1mp3v7cj0rxz0qakf-libfabric-1.4.1.tar.bz2
/gnu/store/vh8syjrsilnbfcf582qhmvpg1v3rampf-rdma-core-14.tar.gz
...

(Nel caso ti stia chiedendo, si tratta di più di 320 MiB di codice sorgente compressed.)

Possiamo quindi creare un grande archivio contenente tutto questo (vedi Invocare guix archive in Manuale di riferimento di GNU Guix):

$ guix archive --export \
 `guix build --sources=transitive openmpi` \
 > openmpi-source-code.nar

… e possiamo eventualmente trasferire quell’archivio al cluster su memoria rimovibile e decomprimerlo lì:

$ guix archive --import < openmpi-source-code.nar

Questo processo deve essere ripetuto ogni volta che è necessario portare nuovo codice sorgente al cluster.

Mentre scriviamo, gli istituti di ricerca coinvolti in Guix-HPC non hanno cluster isolati. Se hai esperienza con tali configurazioni, ci piacerebbe ricevere il tuo feedback e suggerimenti.


Successivo: , Precedente: , Su: Installare Guix su un Cluster [Contenuti][Indice]

10.4 Utilizzo del Disco

Una preoccupazione comune degli amministratori di sistema è se tutto questo consumerà molto spazio su disco. Semmai, se qualcosa esaurirà lo spazio su disco, saranno i set di dati scientifici piuttosto che il software compilato — questa è la nostra esperienza con quasi dieci anni di utilizzo di Guix sui cluster HPC. Ciononostante, vale la pena dare un’occhiata a come Guix contribuisce all’utilizzo del disco.

Innanzitutto, avere diverse versioni o varianti di un dato pacchetto in /gnu/store non costa necessariamente molto, perché guix-daemon implementa la deduplicazione di file identici, e le varianti dei pacchetti probabilmente avranno un certo numero di file comuni.

Come accennato in precedenza, consigliamo di avere un cron job per eseguire guix gc periodicamente, che rimuove il software unused da /gnu/store. Tuttavia, c’è sempre la possibilità che gli utenti mantengano molto software nei loro profili, o molte vecchie generazioni dei loro profili, che è “vivo” e non può essere eliminato dal punto di vista di guix gc.

La soluzione a questo è che gli utenti rimuovano regolarmente le vecchie generazioni del loro profilo. Ad esempio, il seguente comando rimuove le generazioni più vecchie di due mesi:

guix package --delete-generations=2m

Allo stesso modo, è una buona idea invitare gli utenti ad aggiornare regolarmente il proprio profilo, il che può ridurre il numero di varianti di un dato pezzo di software memorizzato in /gnu/store:

guix pull
guix upgrade

Come ultima risorsa, è sempre possibile per gli amministratori di sistema fare parte di questo per conto dei loro utenti. Tuttavia, uno dei punti di forza di Guix è la libertà e il controllo che gli utenti ottengono sul loro ambiente software, quindi raccomandiamo vivamente di lasciare gli utenti in controllo.


Precedente: , Su: Installare Guix su un Cluster [Contenuti][Indice]

10.5 Considerazioni sulla Sicurezza

Su un cluster HPC, Guix è tipicamente usato per gestire software scientifico. Software critici per la sicurezza come il kernel del sistema operativo e i servizi di sistema come sshd e lo scheduler di batch rimangono sotto il controllo degli amministratori di sistema.

Il progetto Guix ha un buon track record nel fornire aggiornamenti di sicurezza in modo tempestivo (vedi Aggiornamenti di sicurezza in Manuale di riferimento di GNU Guix). Per ottenere gli aggiornamenti di sicurezza, gli utenti devono eseguire guix pull && guix upgrade.

Poiché Guix identifica in modo univoco le varianti del software, è facile vedere se un pezzo di software vulnerabile è in uso. Ad esempio, per verificare se la variante glibc 2.25 senza la patch di mitigazione contro “Stack Clash”, si può controllare se i profili utente vi fanno riferimento in assoluto:

guix gc --referrers /gnu/store/...-glibc-2.25

Questo riporterà se esistono profili che fanno riferimento a questa specifica variante di glibc.


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

11 Gestione del Sistema Guix

Poiché Guix non gestisce il packaging, la configurazione del sistema e i servizi nel modo in cui lo fanno altre distribuzioni (più “classiche”), alcuni flussi di lavoro tendono a svolgersi in modo leggermente diverso da come siamo abituati e necessitano di un leggero adattamento. Questo capitolo intende aiutare con tali questioni.


Su: Gestione del Sistema Guix [Contenuti][Indice]

11.1 Aggiornare Postgres per Cuirass

Con la deprecazione del valore predefinito per il pacchetto postgres in postgresql-configuration (vedi b93434e656eba4260df82158a96c295000d3ff44), gli aggiornamenti di sistema richiedono alcune azioni manuali prima di poter aver luogo. Ecco una pratica guida su come fare.

Si prega di notare che questo è un modo diretto per dataset più piccoli. Per database più grandi pg_upgrade potrebbe essere la scelta migliore. La gestione del servizio e l’aggiornamento del sistema come descritto in questa guida si applicano comunque.

  1. Ferma e disabilita cuirass.

    Impedisci al servizio di avviarsi e fallire dopo una riconfigurazione:

    sudo herd stop cuirass && sudo herd disable cuirass

  2. Scarica il contenuto del database.

    sudo su - postgres -s /bin/sh -c pg_dumpall > /tmp/pg.dump

  3. Aggiungi o modifica il servizio postgres.

    A seconda che il tuo servizio postgres sia definito implicitamente (tramite la dipendenza dal servizio cuirass) o con una propria voce nella proprietà (services) del tuo sistema operativo, devi aggiungere o modificare la configurazione esistente per riflettere l’aggiornamento della versione desiderata.

    Fai attenzione a non aggiornare direttamente a postgres-16 – il servizio cuirass per qualche motivo non lo gradisce. Ho dovuto trovare ed eliminare i file rilevanti e poi reinizializzare dopo un aggiornamento fallito a postgres 16.

    (service postgresql-service-type
     (postgresql-configuration
     (postgresql (@ (gnu packages databases) postgresql-15))))
    

    Nota: Se per qualche motivo non hai letto il testo qui ma hai seguito ciecamente gli esempi e hai aggiornato alla versione 16, ecco come reimpostare lo stato:

    1. Elimina i file dell’istanza del database.

      Per impostazione predefinita si trovano in /var/lib/postgres/data.

    2. Reinizializza postgres.

      sudo su - postgres -s /bin/sh -c 'pg_ctl init -D /var/lib/postgres/data'

  4. Riconfigura il tuo sistema.

    sudo guix system reconfigure path/to/your/altered/config.scm

  5. Ripristina il contenuto del database.

    sudo su - postgres -s /bin/sh -c 'psql -d postgres -f /tmp/pg.dump'

  6. Abilita e avvia il servizio.
    sudo herd enable cuirass
    sudo herd start cuirass
    

Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

12 Ringraziamenti

Guix è basato sul gestore di pacchetti Nix, progettato e implementato da Eelco Dolstra, con contributi di altre persone (vedi il file nix/AUTHORS in Guix). Nix ha aperto la strada alla gestione funzionale dei pacchetti e ha promosso funzionalità senza precedenti, come gli aggiornamenti e i rollback transazionali dei pacchetti, i profili per utente e i processi di costruzione referenzialmente trasparenti. Senza questo lavoro, Guix non esisterebbe.

Le distribuzioni software basate su Nix, Nixpkgs e NixOS, sono state anche un’ispirazione per Guix.

GNU Guix stesso è un lavoro collettivo con contributi di diverse persone. Consulta il file AUTHORS in Guix per maggiori informazioni su queste persone. Il file THANKS elenca le persone che hanno contribuito segnalando bug, curando l’infrastruttura, fornendo grafica e temi, dando suggerimenti e altro ancora — grazie!

Questo documento include sezioni adattate da articoli precedentemente pubblicati sul blog di Guix all’indirizzo https://guix.gnu.org/blog e sul blog di Guix-HPC all’indirizzo https://hpc.guix.info/blog.


Successivo: , Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

Appendice A Licenza di Documentazione Libera GNU

Version 1.3, 3 November 2008
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
https://fsf.org/
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
  1. PREAMBLE

    The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

    This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

    We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

  2. APPLICABILITY AND DEFINITIONS

    This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

    A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

    A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

    The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

    The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

    A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.

    Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

    The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.

    The “publisher” means any person or entity that distributes copies of the Document to the public.

    A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.

    The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

  3. VERBATIM COPYING

    You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

    You may also lend copies, under the same conditions stated above, and you may publicly display copies.

  4. COPYING IN QUANTITY

    If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

    If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

    If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

    It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

  5. MODIFICATIONS

    You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

    1. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
    2. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
    3. State on the Title page the name of the publisher of the Modified Version, as the publisher.
    4. Preserve all the copyright notices of the Document.
    5. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
    6. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
    7. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice.
    8. Include an unaltered copy of this License.
    9. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
    10. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
    11. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
    12. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
    13. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version.
    14. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.
    15. Preserve any Warranty Disclaimers.

    If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.

    You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

    You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

    The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

  6. COMBINING DOCUMENTS

    You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

    The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

    In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”

  7. COLLECTIONS OF DOCUMENTS

    You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

    You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

  8. AGGREGATION WITH INDEPENDENT WORKS

    A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

    If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

  9. TRANSLATION

    Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

    If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

  10. TERMINATION

    You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

    However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

    Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

    Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.

  11. FUTURE REVISIONS OF THIS LICENSE

    The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See https://www.gnu.org/copyleft/.

    Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

  12. RELICENSING

    “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.

    “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

    “Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.

    An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

    The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.

ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

 Copyright (C) year your name.
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3
 or any later version published by the Free Software Foundation;
 with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
 Texts. A copy of the license is included in the section entitled ``GNU
 Free Documentation License''.

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:

 with the Invariant Sections being list their titles, with
 the Front-Cover Texts being list, and with the Back-Cover Texts
 being list.

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.


Precedente: , Su: Ricettario di GNU Guix [Contenuti][Indice]

Indice dei concetti

Salta a: 2
A B C D E G H I K L M N Q R S U W Y
Voce dell’indice Sezione

2
2FA, autenticazione a due fattori:Utilizzo di chiavi di sicurezza

A
amministratore di sistema:Gestione del Sistema Guix

B
bluetooth, configurazione ALSA:Server musicale con audio Bluetooth

C
calcolo ad alte prestazioni, HPC:Installare Guix su un Cluster
canale:Canali
caratteri stumpwm:StumpWM
chiave di sicurezza, configurazione:Utilizzo di chiavi di sicurezza
condividere directory, contenitore:Contenitori Guix

D
disabilitazione OTP yubikey:Utilizzo di chiavi di sicurezza
DNS dinamico, DDNS:Processo mcron per DNS dinamico

E
esporre directory, contenitore:Contenitori Guix
evitare disallineamento ABI, contenitore:Contenitori Guix

G
G-expressions, sintassi:Un corso intensivo di Scheme
gestione del sistema:Gestione del Sistema Guix
gexps, sintassi:Un corso intensivo di Scheme

H
HPC, calcolo ad alte prestazioni:Installare Guix su un Cluster

I
impacchettamento:Impacchettamento
installazione cluster:Installare Guix su un Cluster
integrazione continua (CI):Configurazione dell'integrazione continua
Interfaccia bridge di rete:Ponte di rete per QEMU
Interfaccia bridge di rete virtuale:Rete instradata per libvirt

K
kimsufi, Kimsufi, OVH:Eseguire Guix su un Server Kimsufi

L
libvirt, switch di rete virtuale:Rete instradata per libvirt
licenza, GNU Free Documentation License:Licenza di Documentazione Libera GNU
linode, Linode:Eseguire Guix su un Server Linode
lock files, for reproducibility:Recording the Environment

M
mappare posizioni, contenitore:Contenitori Guix
mpd:Server musicale con audio Bluetooth

N
nascondi librerie di sistema, contenitore:Contenitori Guix
networking del contenitore:Networking dei contenitori
networking, bridge:Ponte di rete per QEMU
networking, bridge virtuale:Rete instradata per libvirt
nginx, lua, openresty, resty:Configurazione di NGINX con Lua

Q
qemu, bridge di rete:Ponte di rete per QEMU

R
reproducible research:Reproducible Research

S
S-expression:Un corso intensivo di Scheme
Scheme, corso intensivo:Un corso intensivo di Scheme
server musicale, headless:Server musicale con audio Bluetooth
sessionlock:Blocco sessione
sicurezza, su un cluster:Considerazioni sulla sicurezza del cluster
stumpwm:StumpWM
sviluppo software, con Guix:Sviluppo software
sviluppo, con Guix:Sviluppo software

U
U2F, Secondo Fattore Universale:Utilizzo di chiavi di sicurezza
uscire da un contenitore:Contenitori Guix
utilizzo del disco, su un cluster:Utilizzo del disco del cluster

W
wm:Personalizzazione di un Window Manager

Y
yubikey, integrazione keepassxc:Utilizzo di chiavi di sicurezza

Salta a: 2
A B C D E G H I K L M N Q R S U W Y

Note a piè di pagina

(1)

Questo capitolo è adattato da un post del blog pubblicato a giugno 2023 sul sito web di Guix.

(2)

This chapter is adapted from a blog post published on the Guix-HPC web site in 2023..

(3)

Questo capitolo è adattato da un post del blog pubblicato sul sito web di Guix-HPC nel 2017.

AltStyle によって変換されたページ (->オリジナル) /