URL: https://linuxfr.org/news/nix-pour-les-developpeurs Title: Nix pour les développeurs Authors: nokomprendo claudex, Benoît Sibaud, bubar🦥, Davy Defaud, palm123 et ZeroHeure Date: 2017年07月04日T19:20:36+02:00 License: CC By-SA Tags: nix, debian, firefox, flatpak et guix Score: 53 Nix est un gestionnaire de paquets « fonctionnel » (basé sur des fonctions, sans effet de bord). Cette caractéristique apporte des avantages indéniables, notamment de pouvoir mettre en place des environnements logiciels isolés, reproductibles et composables. Ceci peut être très utile à un administrateur système mais également à un développeur. On trouve pas mal d’informations sur [l’écosystème Nix](http://linuxfr.org/news/nix-1-7-nixpkgs-et-nixos-14-04-guix-0-6) et son utilisation, ainsi que des [retours d’expérience des utilisateurs](http://linuxfr.org/users/katyucha/journaux/comment-j-ai-abandonne-debian). En revanche, les documents à destination des développeurs sont moins nombreux et se limitent souvent à [l’utilisation](http://linuxfr.org/news/nixos-14-12-la-distribution-linux-sans-effet-de-bord#d%C3%A9velopper-avec-nix-ou-pourquoi-je-ne-peux-plus-men-passer) ou à la [mise en place](https://ariya.io/2016/06/isolated-development-environment-using-nix) d’environnements de développement simples. Cet article a pour objectif d’illustrer l’intérêt de Nix pour un développeur dans des cas simples et « un peu moins simples ». Pour cela, il se base sur un projet d’exemple en C++ et en Python, mais Nix peut également être utilisé pour d’autres langages. Je ne suis pas un expert en Nix, donc n’hésitez pas à proposer vos remarques ou améliorations dans les commentaires ou sur le [dépôt GitHub du projet d’exemple](https://github.com/nokomprendo/the_checkerboard_project). ---- [Article LinuxFr.org : Nix 1.7, Nixpkgs, NixOS 14.04, Guix 0.6](https://linuxfr.org/news/nix-1-7-nixpkgs-et-nixos-14-04-guix-0-6) [Le projet NixOS](http://nixos.org/) [Le gestionnaire de paquets Nix](http://nixos.org/nix/) [Dépôt GitHub du projet d’exemple](https://github.com/nokomprendo/the_checkerboard_project) ---- # Introduction ## Exemple 1 : créer un environnement de développement de test ### Scénario Vous avez codé un script Python `myscript.py` et vous voulez le tester dans un environnement vierge. ```python # myscript.py import numpy x = numpy.ndarray(42, int) x[0::2] = 13 x[1::2] = 37 print(x) ``` ### Avec les outils classiques (Python, virtualenv, pip) ```bash virtualenv -p /usr/bin/python3 --no-site-packages ~/myvenv source ~/myvenv/bin/activate pip install numpy python myscript.py deactivate rm -rf ~/myvenv ``` ### Avec Nix ```bash nix-shell --pure -p python35Packages.numpy --run "python myscript.py" ``` ## Exemple 2 : reproduire un environnement de développement ### Scénario Vous développez un logiciel `myprog` en C++, compilé avec _Cmake_ et utilisant la bibliothèque _Boost_. Vous avez récupéré votre projet sur une nouvelle machine et voulez le compiler. ### Avec les outils classiques (par exemple sous Arch Linux) ```bash sudo pacman -S gcc cmake boost mkdir build cd build cmake .. make ``` ### Avec Nix Au cours du projet, un fichier `default.nix` est tenu à jour (il indique notamment les dépendances à Cmake et à Boost). Il suffit alors de lancer la commande : ``` nix-build ``` ## Exemple 3 : empaqueter un projet ### Scénario Le projet `myprog` de l’exemple précédent vient d’aboutir à une version 0.1 dont le code source est disponible en ligne. Vous voulez l’installer proprement sur votre système. ### Avec les outils classiques (par exemple sous Arch Linux) ```bash sudo pacman -S base-devel mkdir myprog cd myprog # Écrire un fichier PKGBUILD (avec l’adresse URL de la publication, les dépendances, les instructions de compilation, etc.). makepkg sudo pacman -U myprog-0.1-1-any.pkg.tar.xz ``` Cette solution fonctionne pour Arch Linux uniquement. Si vous voulez une solution pour Debian ou Fedora, il faut créer les paquets Deb ou RPM correspondants. ### Avec Nix ```bash cp default.nix release.nix # dans le fichier release.nix, changer la valeur de la variable src par l’URL de la publication nix-env -f release.nix -i myprog ``` Ici, la solution devrait fonctionner automatiquement pour tout système compatible avec Nix (Arch Linux, Debian, Fedora...). ## Exemple 4 : personnaliser des dépendances ### Scénario Vous développez des logiciels de traitement d’images utilisant la bibliothèque OpenCV. Pour cela, vous utilisez le paquet OpenCV fourni par la logithèque système. Un de vos logiciels doit utiliser GTK ; malheureusement, le paquet OpenCV a été compilé avec l’option `-DWITH_GTK=OFF`. ### Avec les outils classiques [Bienvenue en enfer...](https://en.wikipedia.org/wiki/Dependency_hell) Quelques « solutions » classiques : - recompiler OpenCV à partir du code source ; vous pourrez ensuite faire une installation système (mais cela peut impacter les autres logiciels) ou une installation locale (mais il faudra configurer les chemins vers votre OpenCV personnalisé quand vous en aurez besoin) ; - utiliser un système d’environnement virtualisé (_chroot_, Flatpak, Docker...). Pour cela, vous devrez mettre en place le système, puis récupérer une image d’OpenCV compilé avec les bonnes options ou créer votre propre image. ### Avec Nix Les paquets Nix sont paramétrables. Ainsi pour activer l’option GTK 2 du paquet OpenCV, il suffit (presque) d’ajouter la ligne suivante dans le fichier `default.nix`. La recompilation et la gestion des différentes versions est automatique. ``` opencv3gtk = pkgs.opencv3.override { enableGtk2 = true; }; ``` # Quelques rappels sur Nix ## Présentation Nix est un gestionnaire de paquets fonctionnel. Le terme « fonctionnel » est à prendre au sens mathématique : une fonction prend des entrées et produit une sortie, sans réaliser d’effets de bord. Ceci permet de créer des environnements logiciels (compilation, installation et configuration) avec les avantages suivants : - les environnements sont reproductibles ; - ils sont paramétrables et composables ; - ils n’ont jamais besoin d’être dupliqués ; - ils sont exécutés nativement. L’écosystème Nix comporte différents éléments : - un langage permettant de décrire un environnement logiciel (appelé nix-expression) ; - des outils (_nix-build_, _nix-env_, _nix-shell_...) permettant de construire, installer, exécuter, etc., des nix-expressions ; - un dépôt officiel (_nixpkgs_) de nix-expressions... Il existe une distribution GNU/Linux (NixOS) directement basée sur ces éléments, mais le système Nix peut être installé sur un système d’exploitation quelconque (GNU/Linux, BSD, macOS) pour y servir de logithèque et de système d’environnement virtuel. Enfin, Nix a inspiré un système concurrent, nommé GNU Guix. Tout comme Nix, Guix peut être utilisé sur un système d’exploitation classique ou via une distribution dédiée, GuixSD. À la différence de Nix, Guix est basé sur un langage existant (Guile Scheme) et accorde une plus grande importance à l’aspect « logiciel libre ». ## Quelques commandes Nix - voir les paquets installés : ``` nix-env -q ``` - voir les paquets disponibles contenant le motif "firefox" : ``` nix-env -qa 'firefox' ``` - installer le paquet `firefox` : ``` nix-env -i firefox ``` - désinstaller le paquet `firefox` : ``` nix-env -e firefox ``` Toutes ces commandes sont utilisables avec les droits utilisateurs et dans l’environnement de l’utilisateur. Les paquets sont gérés par un service (_nix-daemon_) qui les installe dans un répertoire commun `/nix/store` et les rend disponibles aux différents utilisateurs. # Projet d’exemple (C++/Python) Pour illustrer l’utilisation de Nix, on considère un projet type (_[the_checkerboard_project](https://github.com/nokomprendo/the_checkerboard_project)_) qui calcule et affiche des images de damier. ![checkerboard](https://raw.githubusercontent.com/nokomprendo/the_checkerboard_project/master/screenshot_checkerboard.png) Ce projet est composé d’une bibliothèque C++ (_checkerboard_) et d’une interface Python (_pycheckerboard_) contenant la liaison proprement dite et un script Python additionnel. ``` the_checkerboard_project/ ├── checkerboard │ ├── CMakeLists.txt │ ├── checkerboard.cpp │ ├── checkerboard.hpp │ └── test_checkerboard.cpp └── pycheckerboard ├── setup.py └── src ├── checkerboard │ └── binding.cpp └── pycheckerboard ├── __init__.py └── test1.py ``` Les fonctions pour calculer un damier et pour afficher une image, en utilisant la bibliothèque OpenCV. La compilation est réalisée via Cmake, qui fait le lien avec OpenCV et qui construit la bibliothèque _checkerboard_ et un exécutable de test. ```cmake # checkerboard/CMakeLists.txt cmake_minimum_required( VERSION 3.0 ) project( checkerboard ) # lien avec OpenCV find_package( PkgConfig REQUIRED ) pkg_check_modules( MYPKG REQUIRED opencv ) include_directories( ${MYPKG_INCLUDE_DIRS} ) # bibliothèque checkerboard add_library( checkerboard SHARED checkerboard.cpp ) target_link_libraries( checkerboard ${MYPKG_LIBRARIES} ) install( TARGETS checkerboard DESTINATION lib ) install( FILES checkerboard.hpp DESTINATION "include" ) # exécutable de test add_executable( test_checkerboard test_checkerboard.cpp ) target_link_libraries( test_checkerboard checkerboard ${MYPKG_LIBRARIES} ) install( TARGETS test_checkerboard DESTINATION bin ) ``` L’interface Python est faite avec Boost Python. La liaison (`binding.cpp`) expose simplement les deux fonctions de la bibliothèque _checkerboard_. Un script additionnel (`test1.py`) fournit une fonction et un programme de test. Le tout est compilé dans un paquet Python en utilisant un script _setuptools/pip_ très classique. ```python # pycheckerboard/setup.py from setuptools import setup, Extension checkerboard_module = Extension('checkerboard_binding', sources = ['src/checkerboard/binding.cpp'], libraries = ['checkerboard', 'boost_python', 'opencv_core', 'opencv_highgui']) setup(name = 'pycheckerboard', version = '0.1', package_dir = {'': 'src'}, packages = ['pycheckerboard'], python_requires = '<3', ext_modules = [checkerboard_module]) ``` # Configuration Nix basique Classiquement (sans Nix), on exécuterait les commandes suivantes pour compiler et installer la bibliothèque _checkerboard_ : ```bash mkdir checkerboard/build cd checkerboard/build cmake .. make sudo make install ``` Nix permet d’exécuter ces commandes automatiquement. Pour cela, il suffit d’écrire un fichier de configuration `default.nix` indiquant le nom du paquet, le chemin vers le code source et les dépendances (voir cette [dépêche sur l’anatomie d’une dérivation Nix](http://linuxfr.org/news/nix-1-7-nixpkgs-et-nixos-14-04-guix-0-6#anatomie-dune-d%C3%A9rivation-nix)). ```nix # checkerboard/default.nix with import {}; with pkgs; stdenv.mkDerivation { name = "checkerboard"; src = ./.; buildInputs = [ cmake pkgconfig opencv3 ]; } ``` Les dépendances spécifiées ici seront installées automatiquement par Nix, si besoin. Ici la dépendance à Cmake implique que la compilation sera réalisée avec Cmake (_cf._ les commandes précédentes). La compilation et l‘installation de la bibliothèque _checkerboard_ peuvent alors être lancées avec la commande : ```bash nix-env -f . -i checkerboard ``` La bibliothèque ainsi que l’exécutable de test sont alors disponibles dans les chemins système, ou plus exactement dans les chemins système vus par l’utilisateur. Cependant, il n’est pas obligatoire d’installer le paquet _checkerboard_. On peut simplement lancer un _shell_ dans un environnement virtuel contenant le paquet : ```bash nix-shell ``` Ce mécanisme de _shell_ virtuel propose des fonctionnalités très utiles. Par exemple, partir d’un environnement vierge et exécuter juste une commande dans cet environnement : ```bash nix-shell --pure --run test_checkerboard ``` # Configuration Nix modulaire Au lieu de proposer un paquet complet, on peut découper notre _nix-expression_ (`default.nix`) en plusieurs modules, appelés dérivations, qui pourront alors être réutilisés ou reparamétrés. Par exemple, pour créer une dérivation _opencv3gtk_ et une dérivation _checkerboard_ : ```nix # checkerboard/default.nix { system ? builtins.currentSystem }: let pkgs = import { inherit system; }; in with pkgs; stdenv.mkDerivation rec { opencv3gtk = import ./opencv3gtk.nix { inherit (pkgs) opencv3; }; checkerboard = import ./checkerboard.nix { inherit opencv3gtk; inherit (pkgs) cmake pkgconfig stdenv; }; } ``` Ces deux dérivations sont implémentées dans des fichiers spécifiques, pour faciliter leur réutilisation. Par exemple, pour _checkerboard_ : ```nix # checkerboard/checkerboard.nix { cmake, opencv3gtk, pkgconfig, stdenv }: stdenv.mkDerivation { name = "checkerboard"; src = ./.; buildInputs = [ cmake opencv3gtk pkgconfig ]; } ``` Ici, la deuxième ligne indique les paramètres du paquet (c’est‐à‐dire les dépendances à utiliser pour Cmake, _pkgconfig_, etc.). Ce mécanisme permet de composer les paquets de façon très puissante. Par exemple, on peut reparamétrer le paquet OpenCV en activant la prise en charge de GTK (qui n’est pas activée par défaut) et composer ce nouveau paquet à notre paquet _checkerboard_, qui disposera alors des fonctionnalités GTK. On peut même modifier finement les options de compilation du paquet OpenCV (par exemple, désactiver les en‐têtes pré‐compilés qui consomment beaucoup de mémoire vive) : ```nix # checkerboard/opencv3gtk.nix { opencv3 }: let opencv3gtk = opencv3.override { enableGtk2 = true; }; in opencv3gtk.overrideDerivation ( attrs: { cmakeFlags = [attrs.cmakeFlags "-DENABLE_PRECOMPILED_HEADERS=OFF"]; } ) ``` Bien entendu, reparamétrer un paquet nécessite une recompilation si le paquet n’a pas déjà été compilé pour ce jeu de paramètres. Notez que le nouveau `default.nix` ne contient pas de dérivation par défaut. Il faut donc préciser la dérivation à utiliser ou à installer : ```bash nix-shell -A checkerboard nix-env -f . -iA checkerboard ``` # Configuration Nix pour un paquet Python De nombreux langages proposent leur propre système de gestion de paquets (_pip_ pour Python, _gem_ pour Ruby, _npm_ pour JavaScript, etc.). Nix fournit des fonctionnalités pour créer ce genre de paquets. Par exemple, pour créer un paquet Python de notre projet, on peut écrire un fichier `default.nix`, qui va réutiliser les dérivations _opencv3gtk_ et _checkerboard_ précédentes. Nix fournit une fonction _buildPythonPackage_ qui permet de créer simplement un paquet Python en utilisant le script `setuptools/pip` : ```nix # pycheckerboard/default.nix { system ? builtins.currentSystem }: let pkgs = import { inherit system; }; opencv3gtk = import ../checkerboard/opencv3gtk.nix { inherit (pkgs) opencv3; }; checkerboard = import ../checkerboard/checkerboard.nix { inherit opencv3gtk; inherit (pkgs) cmake pkgconfig stdenv; }; in with pkgs; pythonPackages.buildPythonPackage { name = "pycheckerboard"; src = ./.; buildInputs = [ checkerboard python27Packages.boost opencv3gtk ]; } ``` Comme pour la bibliothèque, on peut alors installer la dérivation ou la tester interactivement dans un _shell_ virtuel. Les dépendances _opencv3gtk_ et _checkerboard_ correspondent aux dérivations de la section précédente et ne seront pas recompilées ni dupliquées. ``` $ cd pycheckerboard $ nix-shell --pure --run python Obtaining file:///home/nokomprendo/the_checkerboard_project/pycheckerboard Installing collected packages: pycheckerboard ... Python 2.7.13 (default, Dec 17 2016, 20:05:07) >>> import pycheckerboard.test1 as pt>>> pt.test1() running test1.py... ``` # Conclusion Nix permet de définir des environnements logiciels reproductibles, paramétrables et composables. Il suffit d’écrire quelques fichiers `.nix` qui viennent compléter les outils de compilation classiques du projet. Les paquets ainsi créés peuvent ensuite être installés ou exécutés, éventuellement dans un environnement isolé. Nix gère automatiquement la compilation, les dépendances et les différentes versions de paquets. Ces fonctionnalités sont intéressantes pour un développeur, car elles permettent non seulement de simplifier le déploiement, mais également d’offrir un environnement de développement multi‐langage léger et reproductible.

AltStyle によって変換されたページ (->オリジナル) /