Partie 4 : Contraindre une dérivation
Lecture 6 min. âą
Table des matiĂšres
- Bilan de la situation
- Rendre le builder déterministe
- Rendre <nixpkgs> déterministe
- Simplifier notre dérivation
- Conclusion
Bonjour Ă toutes et tous! đ
QuatriĂšme article sur Nix.
Bilan de la situation
Dans la partie 3, nous avons réussi à compiler du C.
Cependant, nous nâavons pas tout fixĂ©, seuls nos sources sont dĂ©terministes.
On a deux points flottants:
- le
/bin/shon ne sait pas dâoĂč il vient - la dĂ©rivation du
gccvient dâun<nixpkgs>dont on ne connait pas la version

Rendre le builder déterministe
Pour cela, nous allons déjà déterminer le /bin/sh qui est-il? que fait-il dans sa vie?
Générons une dérivation.
nix-repl> 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 1\n");
}
'';
}
«derivation /nix/store/i8r1j3d07w4rnzaj7rlsyh08jz2yc04f-hello-world.drv»Et buildons lĂ en mode verbose Ă lâextĂ©rieur du repl.
$ nix-build -vvv /nix/store/zhv7hwhhhql4jk8qklidwi0kdkkj9593-hello-world.drv 2>&1 | grep "sandbox setup: bind mounting"
sandbox setup: bind mounting '/nix/store/7b943a2k4amjmam6dnwnxnj8qbba9lbq-busybox-static-x86_64-unknown-linux-musl-1.35.0/bin/busybox' to '/nix/store/zhv7hwhhhql4jk8qklidwi0kdkkj9593-hello-world.drv.chroot/bin/sh'LĂ câest un peu les entrailles de la bĂȘte.
Pour Ă©viter tout parasites extĂ©rieurs, les builds de Nix sont rĂ©alisĂ©s dans une sandbox logicielle oĂč tout est contrĂŽlable.
Lâune des Ă©tapes, consiste Ă ajouter dans cette sandbox, un exĂ©cutable /bin/sh provenant dâune version de busybox.
Mais cette version, est totalement dĂ©pendante de lâinstallation de Nix pour lâenvironnement de build et donc dĂ©pendant notamment de la version de Nix elle-mĂȘme.
Pour Ă©viter le fameux, âmais ça marche sur mon laptopâ.
Nous devons vérouiller ce comportement.
Pour cela nous allons utiliser un bash provenant dâune dĂ©rivation que lâon souhaite devenir fixe.
nix-repl> :b derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "${pkgs.bash}/bin/bash";
args = [
"-c"
''
gcc $SOURCE -o $out
''
];
PATH = "${pkgs.gcc}/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
void main() {
printf("Hello World 1\n");
}
'';
}
This derivation produced the following outputs:
out -> /nix/store/9rsg6zcismripg13mqi4yrmws5i9hq7j-hello-worldOk, mais nous avons juste caché la poussiÚre sous le tapis.
Le problĂšme reste entier, on ne sait pas ce quâest <nixpkgs>, ou plutĂŽt son Ă©tat dĂ©pend de lâĂ©tat dâinstallation de Nix.
Ce nâest pas reproductible.

Rendre <nixpkgs> déterministe
Heureusement, il est également possible de fixer cela également.
<nixpkgs> nâest dans les faits quâune itĂ©ration parmis dâautres du projet nixpkgs.
Nix fourni des outils pour rechercher de la donnĂ©e venant dâinternet, comme fetchGit ou fetchTarball.
nix-repl> builtins.fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/refs/tags/22.11.tar.gz";
}
"/nix/store/nkhjmzkf9hky9h34yrfy0cgyd9pbh03v-source"
nix-repl> builtins.fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/refs/tags/22.05.tar.gz";
}
"/nix/store/di36mqc6y19ivaa4qjrb2l82c6dqg7m3-source"On a bien une unicitĂ© de lâempreinte selon la version de nixpgs que lâon tĂ©lĂ©charge.
Voyons un peu ce quâil y a dedans.
$ tree -L 1 /nix/store/nkhjmzkf9hky9h34yrfy0cgyd9pbh03v-source
/nix/store/nkhjmzkf9hky9h34yrfy0cgyd9pbh03v-source
âââ CONTRIBUTING.md
âââ COPYING
âââ default.nix
âââ doc
âââ flake.nix
âââ lib
âââ maintainers
âââ nixos
âââ pkgs
âââ README.mdLe dossier pkgs nous intĂ©resse. ^^
Fonction en Nix
Si je vous donne directement la mĂ©thode pour rĂ©cupĂ©rer le pkgs de notre tarball vous aller avoir une syncope, donc nous allons y aller progressivement. đ
Cela, va nous donner un prĂ©texte pour manipuler du Nix et un peu mieux comprendre ce que lâon fera dans les parties suivantes. ^^
Dâabord la notion fonction en Nix.
Le x Ă gauche des deux-points : est le paramĂštre de la fonction. Ce qui est Ă droite est le corps de la fonction.
Cette fonction est stockée dans la varible inc.
Qui peut ensuite ĂȘtre appelĂ©e et donc Ă©valuĂ©e avec une valeur, ici 2.
nix-repl> inc = x : x + 1
nix-repl> inc 2
3On peut mettre autant de paramĂštres que lâon veut, il suffit de les sĂ©parer par des :. Le dernier Ă©lĂ©ment sera le corps de la fonction.
nix-repl> inc_by = x : by : x + by
nix-repl> inc_by 4 3
7En vrai, il sâagit dâune fonction qui renvoit une fonction.
nix-repl> inc_by = x : ( by : x + by )
nix-repl> inc_by 4 3
7Une fonction peut Ă©galement prendre un set comme paramĂštre dâentrĂ©e.
Ici un set Ă deux attributs:
- x
- by
Pour lâappeler, il faut donc lui passer le set correspondant.
{
x = 7;
y = 3;
}nix-repl> inc_by_object = { x, by } : x + by
nix-repl> inc_by_object { x = 7; by = 3; }
10Attribut par défaut
Il est Ă©galement possible dâomettre un paramĂštre en fournissant un attribut par dĂ©faut.
Via la syntaxe
{ x ? 3 } : xSi x est dĂ©fini dans le paramĂštre dâentrĂ©, alors il est utilisĂ©, sinon câest la valeur 3 qui remplace x.
On peut alors utiliser cette propriété:
nix-repl> inc_by_object_optional = { x, by ? 1 } : x + by
nix-repl> inc_by_object_optional { x = 7; by = 3; }
10
nix-repl> inc_by_object_optional { x = 7; }
8Contexte
Nix, possĂšde une autre particularitĂ©, il sâagit des contextes.
let default = 12;
in
{ x ? default } : xlet dĂ©finit quâune variable est dĂ©clarĂ©e et que celle-ci est disponible dans le contexte suivant le mot-clef in.
nix-repl> l = let default = 12;
in
{ x ? default } : x
nix-repl> l { x = 3; }
3
nix-repl> l {}
12Si lâon passe un objet contenant un attribut x, il est utilisĂ©, si on ne passe rien câest default qui sera Ă©valuĂ© en tant que x.
Petit sucre syntaxique.
Il nâest pas nĂ©cessaire de stocker la fonction et son contexte dans une variable, nous pouvons lâappeler directement.
nix-repl> ( let default = 12;
in
{ x ? default } : x ) {}
12
nix-repl> ( let default = 12;
in
{ x ? default } : x ) { x = 3; }
3Import
Enfin, la méthode import permet de charger les dérivations dans le contexte.
nix-repl> nixpkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.05.tar.gz") {}
nix-repl> nixpkgs.pkgs.gcc
«derivation /nix/store/91r1rsrc9mjh8xcppfm071lv8p46a45a-gcc-wrapper-10.3.0.drv»Le bout du chemin
Si vous avez survĂ©cu jusque lĂ , fĂ©licitations Ă vous. đ
Il est temps de rassembler le tout.
Dans lâordre:
- on
fetchTarballles sources Ă la version voulue - on
importles dérivations - on stocke dans la variable
nixpkgsles dérivations - on défini avec
letetinun contexte oĂčnixpkgsexiste - dans ce contexte on crĂ©er une fonction qui prend un paramĂštre optionel
pkgsqui a pour valeur par défautnixpkgs.pkgs - le corps de cette fonction est notre dérivation utilisant le paramÚtre
pkgs. - on appelle la fonction sans paramĂštre ce qui a pour effet de dĂ©clencher lâutilisation de la valeur par dĂ©faut du champ
pkgs, donc la valeur depkgs == nixpkgs.pkgs
En code ça donne ça:
(let
nixpkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {} ;
in
{ pkgs ? nixpkgs.pkgs } :
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "${pkgs.bash}/bin/bash";
args = [
"-c"
''
gcc $SOURCE -o $out
''
];
PATH = "${pkgs.gcc}/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
void main() {
printf("Hello World\n");
}
'';
}){}On est dâaccord, câest pas top. Mais jâai pas trouvĂ© plus simple⊠(câest faux) đ„Č
Par contre, câest pratique pour tester notre thĂ©orie ^^
nix-repl> :b (let
nixpkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.05.tar.gz") {} ;
in
{ pkgs ? nixpkgs.pkgs } :
derivation { ... }){}
This derivation produced the following outputs:
out -> /nix/store/15xyifj30dmivl2j5frfym0081wmi7p9-hello-world
nix-repl> :b (let
nixpkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {} ;
in
{ pkgs ? nixpkgs.pkgs } :
derivation { ... }){}
This derivation produced the following outputs:
out -> /nix/store/dab6w96pj7vgrw3n64kk4c8d819w08lc-hello-world
Pour deux <nixpkgs> diffĂ©rents, nous avons bien deux empreintes diffĂ©rentes et reproductibles ! đ
On peut cocher tout le monde ^^

Simplifier notre dérivation
Alors en fait, on peut dratisquement simlplifier tout ça, mais je ne lâai trouvĂ© quâaprĂšs coup⊠^^â
La premiĂšre avancĂ©e, est quâon peut se dĂ©barasser de la fonction et de lâattribut optionnel.
Opérateur with
En utilisant le mot clef with, qui a pour rÎle de démonter une structure et de mettre chacun de ses attributs dans le contexte courant.
Donc pkgs de nixpkgs.pkgs devient disponible aprÚs le with pour le corps de la dérivation.
let
nixpkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {};
in
with nixpkgs;
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "${pkgs.bash}/bin/bash";
args = [
"-c"
''
gcc $SOURCE -o $out
''
];
PATH = "${pkgs.gcc}/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
void main() {
printf("Hello World\n");
}
'';
}Se débarasser du contexte
Et comme nous nâavons pas non plus besoin dâisolation de contexte, on peut Ă©galement faire sauter le let et le in
with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {};
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "${pkgs.bash}/bin/bash";
args = [
"-c"
''
gcc $SOURCE -o $out
''
];
PATH = "${gcc}/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
void main() {
printf("Hello World\n");
}
'';
}Et lĂ tout de suite, ça respire! đ
Jâai laissĂ© dans lâarticle le chemin de croix, parce que ça fait manipuler le langage et câest pas pire, mĂȘme si le rĂ©sultat Ă©tait dĂ©sastreux. đ€Ł
Remarque
PATH = "${pkgs.gcc}/bin";Peut se remplacer en
PATH = "${gcc}/bin";Car,
<nixpkgs>expose directementpkgs, lâimport est donc capable dâaller chercher les dĂ©rivations du dossierpkgset de les exposer.
Conclusion
Nous avons enfin une dérivation reproductible capable de compiler du C.
Dans la partie 5, nous verrons comment déporter les sources de la dérivations.
Merci de votre lecture â€ïž
