Partie 3 : Première utilisation de Nixpkgs
Bonjour à toutes et tous! 😀
Troisième article sur Nix.
Nixpkgs
Dans la partie 2, nous avons réalisé une dérivation, mais elle ne fait quasiment rien, et surtout pas ce que l'on veut.
C'est à dire compiler du C.
On a besoin de plus! On a besoin d'un compilateur! On a besoin de gcc.
Et donc de sa dérivation ou au moins de son paquet.
Pour cela nous allons appeler repl différemment.
Nous rajoutons un argument --file '<nixpkgs>
.
$ nix repl --file '<nixpkgs>'
Welcome to Nix 2.15.0. Type :? for help.
Loading installable ''...
Added 18779 variables.
Ah! Il y a du changement, il nous dit qu'il a chargé plein de variables.
Le '<nixpkgs>' est un alias pour dire d'aller chercher toutes les dérivations de nixpkgs, le repo officiel de Nix.
Donc maintenant dans votre repl, vous avez accès à toutes les dérivations qui ont pu être faites par la communautée.
Exemple, gcc
.
Lorsque l'on a fait un
On a dans les faits déclaré un environnement où le paquet "gcc" était disponible.
Dans le repl, on peut faire de même, la variable qui nous intéresse est pkgs
, elle contient toutes les dérivations. Dont celle de gcc.
nix-repl> pkgs.gcc
«derivation /nix/store/wfb8f6nsrnfhpw7ya1dwj3k9d4vx6li1-gcc-wrapper-12.2.0.drv»
On peut d'ailleurs aller voir à quoi elle ressemble.
$ nix derivation show /nix/store/wfb8f6nsrnfhpw7ya1dwj3k9d4vx6li1-gcc-wrapper-12.2.0.drv
{
"/nix/store/wfb8f6nsrnfhpw7ya1dwj3k9d4vx6li1-gcc-wrapper-12.2.0.drv": {
"args": [
"-e",
"/nix/store/6xg259477c90a229xwmb53pdfkn6ig3g-default-builder.sh"
],
"name": "gcc-wrapper-12.2.0",
"builder": "/nix/store/dsn6vl7x1hbn1akgpxync19gpx2dzy8w-bootstrap-tools/bin/bash",
"env": {
"out" : "/nix/store/nlgyw2fv0cm8rkz8qm1jyw78vyif1bl9-gcc-wrapper-12.2.0",
...
}
"system": "x86_64-linux",
...
}
}
( J'ai tronqué plein de champ, sinon c'était trop long )
Mais comme vous pouvez le voir, ça reste une dérivation "classique".
Builder avec gcc
Testons d'appeler gcc dans notre builder.
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "/bin/sh";
args = [
"-c"
''
gcc --version > $out
''
];
}
error: builder for '/nix/store/bfrw7x8b09r53fkhmif89jslcv0zr0fp-hello-world.drv' failed with exit code 127;
last 1 log lines:
> sh: gcc: not found
For full logs, run 'nix-store -l /nix/store/bfrw7x8b09r53fkhmif89jslcv0zr0fp-hello-world.drv'.
Arf! 😩
Bon petite expérience, où est gcc sur le disque?
Ok, donc c'est du "$out/bin/gcc". Très bien.
Retour au repl.
nix-repl > "${pkgs.gcc}"
[nix-shell:~/Documents/Workshop/nix/hello]$ which gcc
/nix/store/nlgyw2fv0cm8rkz8qm1jyw78vyif1bl9-gcc-wrapper-12.2.0
Ok, donc interpoler une dérivation donne le chemin de sortie de cette dérivation
nix-repl > "${pkgs.gcc}/bin/gcc"
[nix-shell:~/Documents/Workshop/nix/hello]$ which gcc
/nix/store/nlgyw2fv0cm8rkz8qm1jyw78vyif1bl9-gcc-wrapper-12.2.0/bin/gcc
On peut également concaténer des chaîne de caratères. Maintenant le chemin est complet.
Plus qu'à l'introduire dans le builder et l'affaire est dans le sac.
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "/bin/sh";
args = [
"-c"
''
${pkgs.gcc}/bin/gcc --version > $out
''
];
}
This derivation produced the following outputs:
out -> /nix/store/kzwd92if64f115pvg46n7sdc1x2wp6ir-hello-world
nix-repl> :e /nix/store/kzwd92if64f115pvg46n7sdc1x2wp6ir-hello-world
gcc (GCC) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Et boom ! on a gcc ! 💥
Modifier le PATH
Oui mais c'est pas top, les scripts de build standards n'auront jamais ${pkgs.gcc}/bin/gcc
seulement gcc
.
Pour résoudre le problème, on doit ramener gcc dans le PATH du builder
On va introduire une nouvelle règle de la fonction derivation.
Qui dit que l'on peut générer des variables d'environnements comme bon nous semble.
Exemple:
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "/bin/sh";
value = "tata";
args = [
"-c"
''
echo $value > $out
''
];
}
This derivation produced the following outputs:
out -> /nix/store/l0zl8hhcpywsvzzgmyxzxjf61hyqwq4i-hello-world
nix-repl > :e /nix/store/l0zl8hhcpywsvzzgmyxzxjf61hyqwq4i-hello-world
tata
Nous ce que l'on veut définir c'est "$PATH".
Voyons son contenu.
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "/bin/sh";
args = [
"-c"
''
echo $PATH > $out
''
];
}
This derivation produced the following outputs:
out -> /nix/store/lvjhj4zgqrvcq2sviwhxii5mw3hdali5-hello-world
nix-repl> :e /nix/store/lvjhj4zgqrvcq2sviwhxii5mw3hdali5-hello-world
/path-not-set
Bon, clairement nada ^^
On peut donc s'amuser.
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "/bin/sh";
args = [
"-c"
''
gcc --version > $out
''
];
PATH = "${pkgs.gcc}/bin";
}
This derivation produced the following outputs:
out -> /nix/store/48vlxdr5bhhcgsz7z4plhaxdsbz35i3m-hello-world
nix-repl> :e /nix/store/48vlxdr5bhhcgsz7z4plhaxdsbz35i3m-hello-world
gcc (GCC) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Et re-boom ! on a gcc et pas en format bizare ! 💥💥
Définir des fichiers
Maintenant que nous avons un compilateur, il nous faut des sources.
Nix propose dans sa librairie standard une fonction appelée toFile.
On va faire comme dans l'exemple mais au lieu de déclarer un builder que nous avons déjà, nous allons déclarer le main.c
.
nix-repl> builtins.toFile "main.c" ''
#include "stdio.h"
void main() {
printf("Hello World");
}
''
"/nix/store/9vmwahqfcx6909widh6g9xr736in950q-main.c"
$ file /nix/store/9vmwahqfcx6909widh6g9xr736in950q-main.c
/nix/store/9vmwahqfcx6909widh6g9xr736in950q-main.c: C source, ASCII text
$ cat /nix/store/9vmwahqfcx6909widh6g9xr736in950q-main.c
#include "stdio.h"
void main() {
printf("Hello World");
}
Ok, donc c'est aussi un chemin et dedans nous avons le main.c.
On peut alors définir une variable d'environnement $SOURCE qui contiendra ce chemin.
Puis modifier la commande gcc dans le builder pour compiler.
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "/bin/sh";
args = [
"-c"
''
gcc $SOURCE -o $out
''
];
PATH = "${pkgs.gcc}/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
void main() {
printf("Hello World");
}
'';
}
This derivation produced the following outputs:
out -> /nix/store/m6pd92z8rm9a2ia3qxml096cc33z1g2l-hello-world
Bon, ça marche ^^
Voyons le résultat...
)
Ok, ça sent bon, c'est une executable.
Ben éxécutons-le!
Cool! 😎
Bon, par contre le "$" attaché c'est pas trop.
Faisons une autre version.
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "/bin/sh";
args = [
"-c"
''
gcc $SOURCE -o $out
''
];
PATH = "${pkgs.gcc}/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
void main() {
printf("Hello World\n");
}
'';
}
This derivation produced the following outputs:
out -> /nix/store/807y2c1zj9zz8p8b5ki0a99fkm0lw0w7-hello-world
$ /nix/store/807y2c1zj9zz8p8b5ki0a99fkm0lw0w7-hello-world
Hello World
$
Ah, beaucoup mieux. 😃
Comme vous pouvez l'observez, une minuscule modification dans le main.c, a eu des répercussions dramatiques sur l'empreinte de la dérivation.
- v1 :
m6pd92z8rm9a2ia3qxml096cc33z1g2l-hello-world
- v2 :
807y2c1zj9zz8p8b5ki0a99fkm0lw0w7-hello-world
C'est cela qui permet d'être certain de savoir ce que l'on manipule.
Conclusion
Dans cette partie, nous avons appris à créer une dérivation capable de compiler du C.
Cependant, nous n'avons pas tout fixé, seul nos sources sont déterministes.
Dans la partie 4 nous verrons comment rendre déterministe notre dérivation.
Merci de votre lecture ❤️
Ce travail est sous licence CC BY-NC-SA 4.0.