Partie 2 : Première dérivation
Bonjour à toutes et tous! 😀
Deuxième article sur Nix.
Cette fois-ci, on fait vraiment du Nix.
Mais d'une façon un peu différente de ce que j'ai pu trouver sur internet.
Ok, les dessins vus en partie 1 c'est rigolo, mais en vrai, comment je peux créer ces paquets ?
C'est là que les choses sérieuses débutent! 🥲
Le paquet que l'on veut créer
Nous allons faire le paquet le plus simple du monde.
Un hello-world en C.
Pour cela, il nous faut des sources.
void
Normalement pour compiler on fait un coup de
Et bien allons-y ! Mais utilisons ce qu'on sait déjà faire.
nix-shell -p gcc
On obtient alors un shell avec gcc
)
Compilons et rendons exécutable le fichier
[nix-shell:~/path]$ gcc main.c -o result
[nix-shell:~/path]$ chmod +x result
[nix-shell:~/path]$ ./result
Hello World
[nix-shell:~/path]$ exit
Wouhou, on sait encore faire du C 😎
Découverte de nix-repl
Bon assez rigolé, attaquons les choses sérieuses.
Mais nous allons le faire très progressivement.
Tout d'abord et en dehors d'un nix-shell, nous allons utiliser le REPL "Real Event Print Loop" de Nix. Il s'agit d'un programme qui permet de manipuler Nix en mode interactif.
$ nix repl
Welcome to Nix 2.15.0. Type :? for help.
Si tout se passe bien, vous devriez avoir un affichage semblable.
Il permet de taper des expressions qui seront analysées et exécutées.
nix-repl > 1 + 2
3
La fonction derivation
Créons maintenant, une dérivation dont on a si souvent parlé dans la partie précédente.
nix-repl > derivation
«lambda @ //builtin/derivation.nix:5:1»
Ok, "lambda" ... Cela signifie qu'il s'agit d'une fonction.
En Nix, pour appeler une fonction on fait
expr {}
{% note(title=""() %} Pour les pros, oui je sais c'est un raccourci, j'explicite dans la partie 3 ^^ {% end %}
Allons-y pour la derivation.
nix-repl > derivation {}
error: attribute 'name' missing
Donc la fonction prend un attribut qui est name
;
Les attributs sont les champs de structures de données comme ci-dessous:
{ x = 1; y = 2; }
En Nix on nomme ceci un set
.
Remarquez le point virgule ;
à la fin de chaque attribut
Nous allons donc donner à notre fonction un set comportant l'attribut name
et qui a pour valeur "hello-world".
nix-repl > derivation { name = "hello-world"; }
error: required attribute 'builder' missing
Bon ça progresse ! Je vais pas vous faire tous les attributs manquants, un à un ^^
Voici un set complet
nix-repl > derivation { name = "hello-world"; builder = "fake-builder"; system = "fake-system";}
«derivation /nix/store/z4lc26wzbma1c5s7spp98zz7xz99m5gh-hello-world.drv»
Wouhou ! Vous venez de créer votre première dérivation !
Derivation Nix
Le retour de vous avez créé a tout l'air d'être un chemin sur l'ordi.
Sortons du REPL avec ctrl+d
.
Voyons ce qu'il en est.
C'est bien un fichier, visualisons son contenu.
)
Nix propose une alternative plus sympatique pour le visualiser.
;
Bon, il faut rajouter l'argument.
{
}
{% note(title=""() %} Vu que c'est experimental mais pas complet cassé, nous allons désactiver les warnings.
{% end %}
Dans ce qui ressemble a du JSON, nous avons une clef avec le nom de notre dérivation <deriv> et dedans une clef <deriv>.env.out
.
Celle-ci a pour valeur un autre chemin /nix/store/vzv4g8bavybrp4682xidd5dn7r9w8lf6-hello-world
.
Si on tente de l'atteindre.
Normal, nous avons déclaré notre dérivation mais nous ne l'avons pas encore réalisée.
C'est donc logique et plutôt rassurant que le paquet hello-world
n'existe pas encore.
Réalisation de la dérivation
Réalisons notre dérivation !
Pour cela, nouvelle commande : nix-build
.
Ok, notre dérivation est pas top, je crois que nous allons devoir repartir sur la table à dessins. 😢
On est de retour dans le REPL.
Changeons l'attribut system
pour ce qu'il demande.
nix-repl> derivation { name = "hello-world"; builder = "fake-builder"; system = "x86_64-linux";}
«derivation /nix/store/85pf9z8ps92lf115wpfy5k493l096g99-hello-world.drv»
Le chemin est complètement différent, pour cette seconde dérivation.
$ nix derivation show /nix/store/85pf9z8ps92lf115wpfy5k493l096g99-hello-world.drv
{
"/nix/store/85pf9z8ps92lf115wpfy5k493l096g99-hello-world.drv": {
"builder": "fake-builder",
"env": {
"system": "x86-64_linux"
}
}
}
Et notre système est à la bonne valeur.
On relance un build et on croise les doigts. 🤞
;
> error:
Ah! De l'avancement. des erreurs mais on progresse.
Je trouve le chemin de modification un peu longuet: repl, derivation, exit repl, build.
Est-ce que l'on pourrait rester dans le REPL pour build ? Oui, sinon je poserai pas la question. 😝
Il suffit de rajouter :b
devant la déclaration de la dérivation.
nix-repl> :b derivation { name = "hello-world"; builder = "fake-builder"; system = "x86_64-linux";}
error: builder for '/nix/store/85pf9z8ps92lf115wpfy5k493l096g99-hello-world.drv' failed with exit code 1;
last 1 log lines:
> error: executing 'fake-builder': No such file or directory
For full logs, run 'nix-store -l /nix/store/85pf9z8ps92lf115wpfy5k493l096g99-hello-world.drv'.
Bon il trouve pas le builder, et pour cause, il n'existe pas.
Le builder
Un builder est un exécutable qui a pour but de réaliser la dérivation et de mettre le contenu dans <deriv>.env.out
celui du retour de la commande nix derivation show
..
Pour cela nous allons rajouter un quatrième paramètre args
qui va nous permettre de définir les arguments passés au builder.
Ici ça sera l'équivalent d'écrire:
-c
pour lire le stdin et l'exécuter.
Et nous allons utiliser un builder
qui existe, celui-ci sera /bin/sh
.
J'explique dans la partie 3 pourquoi. ^^
Le env
de <deriv>.env.out
est ici pour signaler qu'une variable d'environnement "$out" est définie à la valeur du chemin de sortie de la dérivation.
Donc ici, notre builder se contente de venir écrire toto à ce chemin. Qui devient un fichier.
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "/bin/sh";
args = [
"-c"
''
echo toto > $out
''
];
}
This derivation produced the following outputs:
out -> /nix/store/alrzzi9kljsqazv5a34hspx531wjknz7-hello-world
On peut s'en convaincre avec:
Félicitation ! Vous venez de réaliser votre première dérivation!! 🎉 🍾
Conclusion
Nous avons bien une dérivation, elle est fonctionnelle, ne compile pas encore de C.
On verra dans la partie 3 comment compiler.
Merci de votre lecture ❤️
Ce travail est sous licence CC BY-NC-SA 4.0.