Le premier type de fichiers que nous allons ajouter au BSP que nous avons produit jusqu’à présent va être assez simple : il s’agira de scripts. L’avantage de ces fichiers est qu’ils ne nécessitent pas de compilation, il suffit de les copier au bon endroit, et avec les bonnes permissions, pour qu’ils soient utilisables sur la cible.
Bien sûr il faut qu’un interpréteur adéquat soit disponible pour les interpréter. Pour les scripts shell cela fait partie de l'environnement de base installé par Yocto, et pour les scripts Python, nous devrons nous assurer de la présence de l'interpréteur et de certains modules supplémentaires.
Avant cela, nous allons commencer par sélectionner une feature (fonctionnalité)
d’image importante : la mise en lecture seule du système
de fichiers. Dans les environnements embarqués, une
préoccupation constante est en effet la corruption des données lors
d’une coupure impromptue de l’alimentation électrique du système.
Lorsqu’elle se produit, cette coupure provoque bien évidemment la perte
des données qui étaient en cours d’enregistrement, mais peut engendrer
une corruption du système de fichiers lui-même. Il devient alors
nécessaire d'exécuter un utilitaire de vérification et de répartion du
système de fichiers (par exemple «e2fsck
»).
Cette action peut être entreprise par des scripts de démarrage qui
montent, vérifient, et réparent si besoin le système de fichiers
concerné.
Le problème devient critique lorsque c'est le système de fichiers
principal (root filesystem, ou rootfs) qui est
atteint, car celui-ci est monté directement par le noyau à la
fin de la phase de boot, juste avant de lancer le processus
«init
».
Le noyau n'a pas accès aux outils de vérification et réparation du système de fichiers, puisque justement ils se trouvent sur ce système de fichiers principal.
Ainsi une corruption, même mineure du système de fichiers principal peut conduire à une impossibilité de démarrer, à un système briqué (i.e.: aussi utile qu'une brique pour ce qui concerne le logiciel)
Il faut bien être conscient qu'une partition accessible en lecture-écriture peut toujours être sujette à ce type de corrution en cas de coupure intempestive de l'alimentation électrique, même si nous ne faisons pas d'écriture intentionnelle sur la partition. Il y a des méta-données (dernière heure de consultation d'un fichier par exemple) qui sont inscrites en permanence.
Une manière simple de corriger ce défaut est de demander à Yocto de monter le système de fichiers contenu sur la partition principale en lecture-seulement. Bien sûr on pourra ajouter des partitions supplémentaires en lecture-écriture pour y stocker des données si besoin, en s’arrangeant pour qu’une détection d’incohérence ne soit pas bloquante, nous en reparlerons. L’important est que la partition principale du système soit protégée.
J’édite donc mon fichier d’image pour ajouter la feature adéquate :
[build-qemu]$ nano ../../layers/meta-my-layer/recipes-custom/images/my-image.bb [...] IMAGE_FEATURES += "read-only-rootfs"
Après re-compilation et démarrage, vérifions le comportement :
mybox login: root Password: (linux) root@mybox:~# pwd /home/root root@mybox:~# echo HELLO > my-file.txt -sh: my-file.txt: Read-only file system
Notre système de fichiers principal est désormais en lecture seule et il n'y a plus de riques de perte de données sur cette partition en cas de coupure intempestive de l'alimentation.
Pendant la phase de mise au point du système embarqué, il peut être pratique de tester des modifications directement dans le système de fichiers avant de les intégrer dans une recette.
Pour cela, il est possible de remonter temporairement la partition principale en lecture-écriture ainsi :
root@mybox:~# mount / -o remount,rw [188.917856] EXT4-fs (vda): re-mounted. Opts: (null) root@mybox:~# echo HELLO > my-file.txt root@mybox:~# ls my-file.txt
Puis de revenir en lecture-seule :
root@mybox:~# mount / -o remount,ro [260.995398] EXT4-fs (vda): re-mounted. Opts: (null) root@mybox:~# rm my-file.txt rm: cannot remove 'my-file.txt': Read-only file system
Néanmoins ces lignes de commandes sont un peu fastidieuses, aussi je
vous propose de réaliser deux petits scripts, que j’appelle
traditionnellement «rw
» et
«ro
» pour réaliser ces tâches. Ceci nous
donnera l’occasion d’écrire une recette pour les intégrer dans notre
image.
Commençons par écrire les deux scripts shell
dans un répertoire dédié de notre layer. Vous pouvez les
télécharger ici :
rw
et
ro
.
[build-qemu]$ mkdir -p ../../layers/meta-my-layer/recipes-custom/my-scripts/files [build-qemu]$ nano ../../layers/meta-my-layer/recipes-custom/my-scripts/files/rw #!/bin/sh mount / -o remount,rw [build-qemu]$ nano ../../layers/meta-my-layer/recipes-custom/my-scripts/files/ro #!/bin/sh mount / -o remount,ro
Inutile de les rendre exécutables, nous ne les lancerons pas sur le système de développement, et leurs permissions sur la cible seront indiquées directement dans notre recette. Nous allons créer manuellement le fichier de recette afin d'en analyser la structure. Créons le fichier suivant :
[build-qemu]$ nano ../../layers/meta-my-layer/recipes-custom/my-scripts/my-scripts.bb SUMMARY = "Custom scripts for Yocto training" SECTION = "custom" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" SRC_URI = "file://ro" SRC_URI += "file://rw" do_install() { install -d ${D}${sbindir} install -m 0755 ${WORKDIR}/ro ${D}${sbindir} install -m 0755 ${WORKDIR}/rw ${D}${sbindir} } FILES:${PN} += "${sbindir}/ro" FILES:${PN} += "${sbindir}/rw"
Quelques explications sur la syntaxe de notre première recette complète :
SUMMARY
et
SECTION
sont purement
informatives et permettent de ranger la recette et la classer
lorsqu’elle est présentée dans une liste comme le site Open
Embedded Layer Index.
LICENSE
le type de licence, et dans
LIC_FILES_CHKSUM
le nom du fichier la décrivant ainsi qu’une somme de contrôle de ce
dernier pour s’assurer que la version est bien identique. Le
projet Yocto lui-même est distribuée sous licence MIT (libre et
sans copyleft), aussi de nombreuses recettes
emploient-elles la même licence. C’est le choix que j’ai fait
ici. Pour éviter de fournir une version du fichier de licence,
j’ai fait référence à celui fourni dans le sous-dossier
meta/files/common-licenses/
de Poky (qui contient près de cinq cents variantes des licences les plus courantes).
La checksum est obtenue avec la commande md5sum
../poky/meta/files/common-licenses/MIT
.
SRC_URI
contient une
liste des fichiers sources utilisés par la recette ainsi que
leur origine. Ici les fichiers sont livrés directement avec la
recette aussi sont-ils préfixés avec
«file://
» mais d’autres descripteurs
de provenance sont disponibles
(«ftp://
»,
«git://
»,
«https://
», etc.). Nous pouvons
remarquer l’usage de l’opérateur «+=
»
pour ajouter un élément dans la liste.
fetch
pour télécharger les sources,
unpack
pour les décompresser, patch
pour les modifier éventuellement, compile
pour
produire le code exécutable, install
pour les
placer dans l’arborescence, etc.). Ces étapes sont
représentées par des fonctions
do_fetch()
,
do_compile()
, etc. qui ont des
implémentations par défaut mais que nous pouvons surcharger.
C’est ce que je fais ici en implémentant
la fonction
do_install()
.
Cette dernière
fait appel à l’utilitaire «install
»
(une sorte de «cp
» plus complet) pour
placer les scripts aux endroits voulus. On notera que l’on
prend soin de créer d'abord les répertoires (même standards)
que l’on utilise avec l’option «-d
»
(directory) de la commande
«install
».
WORKDIR
est automatiquement initialisée avec l’emplacement où Yocto
travaille pour produire la recette. C’est l’endroit où il a
placé les fichiers sources obtenus dans l’étape
do_fetch()
. Notre travail consiste à aller les
installer dans le répertoire désiré de l’arborescence de la
cible. Le point de départ de cette arborescence est toujours
représenté par
la variable D
.
Et la variable sbindir
contient
le sous-répertoire recommandé pour les utilitaires
d’administration (répertoire /usr/sbin
généralement).
FILES
avec la liste des
fichiers dont elle est responsable. On utilise
l’opérateur :${PN}
(Package
Name) pour remplir la variable correspondant à ce package.
Nous avons utilisé la variable sbindir
, il existe toute
une liste de variables prédéfinies avec des chemins standards. Voici
ci-dessous les plus courantes, pour en savoir plus, se reporter au
début du fichier poky/meta/conf/bitbake.conf
.
Variable | Valeur par défaut |
---|---|
bindir | /usr/bin |
datadir | /usr/share |
docdir | /usr/share/doc |
includedir | /usr/include |
infodir | /usr/share/info |
libdir | /usr/lib |
libexecdir | /usr/libexec |
localedir | /usr/lib/locale |
localstatedir | /var |
sbindir | /usr/sbin |
servicedir | /srv |
sysconfdir | /etc |
systemd_unitdir | /lib/systemd |
systemd_system_unitdir | /lib/systemd/system |
systemd_user_unitdir | /usr/lib/systemd/user |
Avant de recompiler l’image, il convient d’inclure notre package dans le fichier d’image :
[build-qemu]$ nano ../../layers/meta-my-layer/recipes-custom/images/my-image.bb [...] IMAGE_INSTALL:append = " my-scripts"
Après compilation et démarrage de la cible, nous vérifions que nos scripts sont bien accessibles et se comportent comme voulu :
My experimental distro 1.0 mybox ttyAMA0 mybox login: root Password: (linux) root@mybox:~# ls root@mybox:~# echo HELLO > my-file -sh: my-file: Read-only file system root@mybox:~# rw [ 47.990109] EXT4-fs (vda): re-mounted 38c30722-c384-46e6-9e66-506cdddbc7a4 r/w. Quota mode: disabled. root@mybox:~# echo HELLO > my-file root@mybox:~# ls my-file root@mybox:~# ro [ 54.424083] EXT4-fs (vda): re-mounted 38c30722-c384-46e6-9e66-506cdddbc7a4 ro. Quota mode: disabled. root@mybox:~# rm my-file rm: cannot remove 'my-file': Read-only file system root@mybox:~#
NB: les messages "EXT4-fs (vda): re-mounted..." ne sont pas des erreurs mais des traces du noyau (nous sommes connectés sur la console principale) lorsqu'une partition est montée ou démontée.
Nous pouvons facilement ajouter des
scripts Python sur
notre cible, un interpréteur Python 3 étant déjà présent dans notre
image, mais le nombre de modules installés par défaut est assez limité.
Nous demanderons, dans notre recette, à disposer de modules supplémentaires.
Vérifions la version de python
installée :
root@mybox:~# python3 -V Python 3.12.3 root@mybox:~#
Je rajoute, dans un répertoire
meta-my-layer/recipes-custom/python-hello/files/
le petit script
python-hello.py
suivant :
#!/usr/bin/python3 # # Christophe BLAESS 2020-2023. # # Licence MIT. # import socket import sys print("Python {} says 'Hello' from {}".format(sys.version[0:3],socket.gethostname()))
Ainsi que la recette
python-hello_1.2.bb
ci-dessous, dans le répertoire
meta-my-layer/recipes-custom/python-hello
.
SUMMARY = "Python Hello World for Yocto tutorial" SECTION = "custom" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" SRC_URI = "file://python-hello.py" RDEPENDS:${PN} += "python3-core" RDEPENDS:${PN} += "python3-modules" do_install() { install -d ${D}${bindir} install -m 0755 ${WORKDIR}/python-hello.py ${D}${bindir} } FILES:${PN} += "${bindir}/python-hello.py"
On peut noter la présence des deux lignes centrales, qui renseignent
la variable RDEPENDS
pour cette recette.
Cette variable, abréviation de Runtime Dependencies contient la
liste des packages nécessaires pour le fonctionnement de la
recette sur la cible.
Il faut la distinguer de la variable
DEPENDS
qui liste les packages nécessaires
pour compiler une recette sur la machine de
développement.
La dépendance de python3-code
et python3-module
permet d'inclure automatiquement sur la cible ces éléments. Il n'existe
pas de packages python3-code
ni python3-module
ce sont des listes définies dans la recette de Python.
En ajoutant dans notre image la ligne :
IMAGE_INSTALL:append = " python-hello"
et en recompilant notre système, nous pouvons observer après démarrage :
My experimental distro 1.0 mybox ttyAMA0 mybox login: root Password: root@mybox:~# python-hello.py Python 3.1 says 'Hello' from mybox
Nous avons vu dans cette séquence comment ajouter dans une image des
fichiers fournis par une recette. Dans le cas d’un script, il faut
simplement penser à lui ajouter les permissions d’exécution (ce qui se
fait facilement avec la commande install
) et
éventuellement l’interpréteur nécessaire. Dans la séquence suivante,
nous écrirons une recette nécessitant une compilation de code source.
Si vous préférez une session de cours interactif, en mode présentiel ou distanciel, n'hésitez pas à vous inscrire à mes formations "Développeur Linux embarqué avec Yocto Project" ou "Yocto Project avancé" .
Ce document est placé sous licence Creative Commons CC BY-NC. Vous pouvez copier son contenu et le réemployer à votre gré pour une utilisation non-commerciale. Vous devez en outre mentionner sa provenance.
Le nom Yocto Project est une marque déposée par la Linux Foundation. Le présent document n'est en aucune façon approuvé par Yocto Project ou la Linux Foundation.