recipetool
Nous avons vu comment ajouter des applications dont les recettes sont livrées avec Poky ou référencées sur Open Embedded Layers Index. Supposons que nous devions adapter de manière plus ou moins importante le contenu d’une de ces recettes.
Comment procéder sans toucher aux fichiers originaux ?
Nous allons le voir dans cette séquence...
Il y a plusieurs manières d’adapter un élément d’une image, qui dépendent du type de modification à effectuer. Notre première approche va consister à remplacer un fichier fourni par une recette.
Pour ce faire, on va commencer par rechercher dans l’arborescence de
Poky le répertoire où se trouve la recette, et examiner les fichiers
présents pour comprendre le mécanisme de construction. Prenons par
exemple l’application psplash
qui affiche une image lors
du boot du système.
Pour trouver l'emplacement d'une recette dont
on connait le nom, on peut utiliser la sous-commande «find-recipe
»
de la commande «devtool
» livrée dans Poky.
[build-qemu]$ devtool find-recipe psplash NOTE: Starting bitbake server... Loading cache: 100% | | ETA: --:--:-- Loaded 0 entries from dependency cache. Parsing recipes: 100% |##################################################################################################| Time: 0:00:28 Parsing of 1874 .bb files complete (0 cached, 1874 parsed). 3212 targets, 126 skipped, 0 masked, 0 errors. Summary: There was 1 WARNING message. /home/Builds/Lab/layers/poky/meta/recipes-core/psplash/psplash_git.bb [build-qemu]$
Examinons le contenu du répertoire de psplash
:
[build-qemu]$ ls ../../layers/poky/meta/recipes-core/psplash/ files psplash_git.bb [build-qemu]$ ls ../../layers/poky/meta/recipes-core/psplash/files/ psplash-init psplash-poky-img.png psplash-poky-img.svg psplash-start.service psplash-systemd.service[build-qemu]$
Le répertoire de base contient un fichier recette au format
.bb
qui indique comment télécharger et compiler
l’application et un sous-répertoire files/
. Dans ce
dernier se trouvent un script de lancement psplash-init
utilisé quand le système démarre à la manière System V, des
fichiers de configuration servant quand le démarrage est géré par
Systemd et un fichier graphique d'extension
.png
qui contient l’image (que nous allons remplacer).
Il est important de bien comprendre que bitbake
charge
d’abord en mémoire toutes les recettes et extensions en analysant leurs
contenus (étape «Parsing recipes
») avant
d’organiser le travail (étape «Initialising
tasks
») puis de réaliser les opérations nécessaires (étape
«Executing RunQueue Tasks
»). Il est donc
possible pour une extension de recette .bbappend
de
venir amender le contenu précédent d’une recette .bb
et
de modifier son comportement.
Nous allons créer dans notre layer un répertoire «psplash
» avec un chemin semblable
à celui de la recette originale dans poky
, et y créer un sous-répertoire
«files/
». L'option «-p
» de mkdir
permet
de créer en une seule fois les trois répertoires imbriqués
[build-qemu]$ mkdir -p ../../layers/meta-my-layer/recipes-core/psplash/files [build-qemu]$
J'ajoute dans le sous-répertoire files/
un fichier PNG que j'ai créé avec
Gimp. J’ai fait plusieurs essais pour obtenir la dimension qui me
convient (et qui est légèrement différente de l’originale). Vous pouvez
créer votre propre image ou
télécharger celle-ci.
[build-qemu]$ ls ../../layers/meta-my-layer/recipes-core/psplash/files/ psplash-poky-img.png
Je vais ensuite créer une extension de recette
ayant le même nom que la recette d'origine mais le suffixe «.bbappend
».
Ce fichier ne contiendra qu'une seule ligne
[build-qemu]$ cat ../../layers/meta-my-layer/recipes-core/psplash/psplash_git.bbappend FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
Il s’agit d’un contenu que l’on retrouve très souvent dans les fichiers
.bbappend
(avec parfois de légères variations).
La partie gauche de l'affectation signifie ici «ajouter au
début» (:prepend
)» de la variable
FILESEXTRAPATHS
.
L’affectation «:=
» indique
que l’interprétation de la partie droite doit se faire dès la lecture
du fichier. Avec une affectation «=
», elle
serait différée au moment de l’analyse de toutes les variables lues.
Ceci nous garantit que l’on prend en compte immédiatement le contenu de
la variable THISDIR
. Comme son nom l'indique, cette
dernière représente le répertoire courant, celui de l'extension de
recette.
La partie droite de l’affectation permet de préciser le sous-dossier
files/
qui est juste à côté de la recette. On notera qu’il
est suivi d’un caractère deux-points «:
» qui
n'a rien à voir avec ceux de la partie gauche. La variable
«FILESEXTRAPATHS
»
contient la liste des chemins
dans lesquels on recherche les fichiers nécessaires pour la réalisation
d’une recette. Les chemins de la liste sont séparés par des deux-points
«:
» et ils sont parcourus dans l’ordre de la
liste.
En ajoutant le répertoire files/
accompagnant cette
extension de recette au début de la liste,
on s’assure que les fichiers
qu’il contient auront précédence sur ceux de la recette initiale.
Ici, le nom du répertoire (files/
) est le même que le
répertoire de la recette initiale, mais cela n'est pas obligatoire.
Nous pouvons alors regénérer et tester notre image.
[build-qemu]$ bitbake my-image
Au démarrage, nous avons le plaisir de voir notre splashscreen personnalisé apparaître comme sur la figure II.3-1.
Nous voyons ainsi comment remplacer un fichier complet proposé par une recette. Cela peut être utile dans de nombreux cas, principalement pour des éléments de configuration système (nous le retrouverons par exemple pour ajuster la configuration du réseau).
Néanmoins d’autres modifications peuvent être nécessaires, celles qui consistent à modifier une petite partie d’un fichier. Par exemple quelques lignes d’un fichier source avant compilation. Pour cela on préfère la méthode du patch.
Nous allons commencer par produire et faire appliquer un
patch sur un fichier fourni directement par une
recette, sans qu'il y ait de compilation. Je vous propose par exemple
de prendre la recette «base-files
»
qui se trouve dans le répertoire meta/recipes-core/
de Poky.
Comme son nom l’indique il s’agit d’une recette qui fournit directement
des fichiers de base situés dans son sous-répertoire
base-files/
. L’un d’eux est
«profile
» qui est copié dans le répertoire
etc/
de la cible. Il configure des variables
d’environnement du shell comme PATH
, PS1
,
TERM
, EDITOR
… avec des valeurs par
défaut que l’utilisateur pourra surcharger s’il le souhaite.
La variable EDITOR
justement, qui indique l’éditeur
préféré de l’utilisateur. Son contenu est pris en compte par exemple
lorsqu'il faut enregistrer un message de commit pour
git
ou éditer un fichier de programmation horaire
(crontab
). Cette variable est initialisée à la valeur
«vi
». Mais nous avons installé sur notre image
l'éditeur nano
, il serait dommage de ne pas en profiter.
Créons donc un patch pour modifier cette ligne du fichier.
Dans le cas (assez rare) où le patch à créer concerne les fichiers
fournis par une recette comme le fichier /etc/profile
, le
plus simple est d'appeler manuellement diff
.
Lorsqu'il s'agira de modification des fichiers d'un projet téléchargé
avec git
par exemple, on préférera faire appel à l'outil
«devtool
» dont nous parlerons prochainement.
Pour commencer je crée une copie temporaire du répertoire
base-files/
qui contient tous les fichiers. Je l’effacerai
quand j’aurai fini de préparer le patch, je reste donc dans mon
répertoire de travail initial.
[build-qemu]$ cp -R ../../layers/poky/meta/recipes-core/base-files/base-files base-files-origin
J’en crée une deuxième copie où je ferai la modification.
[build-qemu]$ cp -R base-files-origin base-files-modified
Puis j’édite le fichier profile
du répertoire
base-files-modified/
pour remplacer la ligne :
EDITOR="vi" # needed for packages like cron, git-commit
par :
EDITOR="nano" # needed for packages like cron, git-commit
Je vérifie que le patch puisse être créé correctement :
[build-qemu]$ diff -ruN base-files-origin/ base-files-modified/ diff -ruN base-files-origin/profile base-files-modified/profile diff -ruN base-files-origin/profile base-files-modified/profile --- base-files-origin/profile 2024-07-26 12:29:48.736573323 +0200 +++ base-files-modified/profile 2024-07-26 12:30:54.326491282 +0200 @@ -66,7 +66,7 @@ fi if [ -z "$EDITOR" ]; then - EDITOR="vi" # needed for packages like cron, git-commit + EDITOR="nano" # needed for packages like cron, git-commit fi export PATH PS1 OPIEDIR QPEDIR QTDIR EDITOR TERM
Le patch est correct, je l’enregistre en créant un répertoire
base-files/
dans notre layer personnalisé, avant
de supprimer les deux répertoires temporaires.
[build-qemu]$ mkdir -p ../../layers/meta-my-layer/recipes-core/base-files/files/ [build-qemu]$ diff -ruN base-files-origin/ base-files-modified/ > ../../layers/meta-my-layer/recipes-core/base-files/files/0001-nano-as-preferred-editor.patch [build-qemu]$ rm -rf base-files-origin/ base-files-modified/
Nous avons obtenu ainsi
notre
fichier de patch. Il doit nécessairement avoir une
extension «.patch
». Il est recommandé de lui
donner un nom significatif (par exemple
nano-as-preferred-editor
) et l'usage veut que le nom
du fichier commence par un nombre qui permettra d'ordonner les
patches dans le cas où plusieurs sont fournis (les
patches pouvant modifier successivement les mêmes fichiers,
l'ordre d'application est important).
Je crée ensuite une extension de recette dans le répertoire
base-files/
de notre layer, en vérifiant au
préalable le nom de la recette à surcharger :
[build-qemu]$ ls ../../layers/poky/meta/recipes-core/base-files/ files base-files_3.0.14.bb
Lorsque le fichier d’extension s’applique à une version spécifique
d’une recette (par exemple 3.0.14
uniquement), on le nomme
base-files_3.0.14.bbappend
.
Attention, le caractère souligné (underscore)
«_
» dans le nom de recette a une
véritable signification : il permet de distinguer le nom du
package (qui ne peut donc pas contenir de souligné, uniquement
des tirets «-
» pour séparer les mots) de son
numéro de version.
Si l'extension s'applique à plusieurs versions de la recette, on
utilise le caractère générique pourcent
«%
» dont le rôle rapelle celui de
l’astérique «*
» dans les motifs du
shell :
base-files_3.%.bbappend
»
s’appliquerait à toutes les recettes de base-files
dont le numéro majeur de version est 3.
base-files_%.bbappend
» s’applique à
toutes les versions.
En toute rigueur un patch s'applique à une version spécifique
d'un fichier, même s'il est peu probable que le fichier
profile
change beaucoup d'une version à l'autre de la
recette base-files
. Je crée donc
la
recette suivante :
[build-qemu]$ nano ../../layers/meta-my-layer/recipes-core/base-files/base-files_3.0.14.bbappend FILESEXTRAPATHS:prepend := "${THISDIR}/files:" SRC_URI += "file://0001-nano-as-preferred-editor.patch"
Comme auparavant nous ajoutons le chemin du sous-répertoire contenant
notre patch dans FILESEXTRAPATHS
.
Notons que l’utilisation de «+=
» ne
fonctionnerait pas, car il utilise toujours une espace comme caractère
de séparation et non un deux-points.
On ajoute notre patch à la liste des fichiers appartenant à la
recette (variable SRC_URI
). Son extension
«.patch
» suffit à ce qu’il soit pris en compte
correctement par bitbake
. On peut relancer la génération
de l’image.
Au moment du build une erreur apparaît qui n'existait pas sur les branches de Poky antérieures à Scarthgap:
[build-qemu]$ bitbake my-image ERROR: base-files-3.0.14-r0 do_patch: QA Issue: Missing Upstream-Status in patch /home/Builds/Lab/layers/meta-my-layer/recipes-core/base-files/files/0001-nano-as-preferred-editor.patch Please add according to https://docs.yoctoproject.org/contributor-guide/recipe-style-guide.html#patch-upstream-status . [patch-status] ERROR: base-files-3.0.14-r0 do_patch: Fatal QA errors were found, failing task. ERROR: Logfile of failure stored in: /home/Builds/Lab/builds/build-qemu/tmp/work/qemuarm-poky-linux-gnueabi/base-files/3.0.14/temp/log.do_patch.3049766 ERROR: Task (/home/Builds/Lab/layers/poky/meta/recipes-core/base-files/base-files_3.0.14.bb:do_patch) failed with exit code '1' NOTE: Tasks Summary: Attempted 2437 tasks of which 2432 didn't need to be rerun and 1 failed.
Le système interne de Yocto chargé de surveiller la qualité du build nous indique
que dorénavant un champ «Upstream-Status
»
doit être présent en entête des patches pour faciliter la maintenance de la recette.
Ce champ indique la situation du patch par rapport à la recette originale sur laquelle il s'applique.
Les valeurs possibles sont :
Pending
» : le patch n'a pas (encore) été soumis au projet upstream.
C'est la valeur que j'adopte lorsque je fais des modifications spécifiques pour le projet qui n'ont pas lieu
d'être soumises au projet initial. Nous utiliserons cet état.
Submitted
» : le patch a été soumis. Lors d'une évolution de la
recette, le mainteneur vérifiera si le patch est toujours d'actualité ou s'il a été appliqué sur le
projet d'origine.
Backport
» : le patch a été soumis et accepté sur le projet upstream.
Lors de la mise à jour de la recette, il faudra supprimer ce patch.
Denied
» : le patch a été refusé dans le projet upstream.
Inactive-Upstream
» : le projet d'origine est inactif depuis longtemps.
Inappropriate
» : le patch n'a pas lieu d'être soumis au projet
upstream. C'est une valeur que je choisis parfois (après avoir hésité avec «Pending
»).
J'ajoute donc une ligne en tout début de mon fichier de patch, qui devient :
Upstream-Status: Pending diff -ruN base-files-origin/profile base-files-modified/profile --- base-files-origin/profile 2024-07-26 02:29:48.736573323 +0200 +++ base-files-modified/profile 2024-07-26 02:30:54.326491282 +0200 [...]
Après rebuild, nous testons notre résultat :
My experimental distro 1.0 mybox ttyAMA0 mybox login: root Password: (linux) root@mybox:~# echo $EDITOR nano root@mybox:~#
La variable d’environnement est bien initialisée avec la modification apportée par notre patch.
Le patch que nous avons développé dans l’exemple précédent était produit et appliqué sur un fichier présent dans une recette. Nous allons à présent voir comment produire un patch s’appliquant sur un fichier source d’un package téléchargé et compilé par une recette.
Pour continuer avec les packages que nous avons déjà installés,
je vous propose de travailler sur le code de l'éditeur nano
.
Pour ce faire, nous pourrions télécharger les sources de nano
,
les extraire, faire notre modification, puis créer un patch
avec diff
comme précédemment ou avec git
par exemple. Une autre solution beaucoup plus adaptée à ce genre de
situation est l'utilisation de la commande
devtool
que nous avons déjà aperçue en début de chapitre
pour rechercher l'emplacement d'un fichier recette.
La force de devtool
est d'être capable de prendre en charge
toutes les actions nécessaires pour créer le patch et l'extension
de recette en nous laissant nous concentrer sur la modification des sources.
Nous commençons par demander à devtool
de nous déployer les
sources dans un répertoire où nous pourrons faire nos modifications.
[build-qemu]$ devtool modify nano NOTE: Starting bitbake server... [...] Initialising tasks: 100% |###############################################################################################| Time: 0:00:00 NOTE: Executing Tasks NOTE: Tasks Summary: Attempted 113 tasks of which 110 didn't need to be rerun and all succeeded. INFO: Source tree extracted to /home/Builds/Lab/builds/build-qemu/workspace/sources/nano INFO: Recipe nano now set up to build from /home/Builds/Lab/builds/build-qemu/workspace/sources/nano [build-qemu]$
En résumé, bitbake
nous indique avoir fait deux choses :
nano
dans le sous-répertoire
«workspace/sources/nano
» de notre répertoire
de travail
bbappend
»
temporaire) la recette de nano
pour que toutes les
compilations à venir se fasse à partir de ce sous-répertoire de fichiers sources.
A tout moment on peut annuler cette situation et revenir à la configuration
précédente avec «devtool reset nano
».
Entrons dans le répertoire des sources de nano
:
[build-qemu]$ cd workspace/sources/nano/ [nano]$ ls ABOUT-NLS COPYING.DOC INSTALL NEWS TODO config.guess config.sub depcomp lib po AUTHORS ChangeLog Makefile.am README aclocal.m4 config.h.in configure doc m4 src COPYING IMPROVEMENTS Makefile.in THANKS compile config.rpath configure.ac install-sh missing syntax [nano]$ git status On branch devtool nothing to commit, working tree clean
Les fichiers sources sont bien présents et une branche spécifique pour git
a été
créée pour nos modifications.
Pour cet exemple, je cherche à faire une modification simple mais assez
facilement visible. Ainsi, je propose de modifier le
texte de bienvenue («Welcome to nano. For basic help,
type CTRL+G.») qui apparaît juste au-dessus des deux
lignes rappelant les raccourcis clavier lorsqu'on lance
«nano
» sans argument. On voit ce texte sur
la figure II.3-2.
Nous pouvons trouver le message de bienvenue dans le fichier
src/nano.c
à la ligne 2551 (dans nano
7.2) :
statusbar(_("Welcome to nano. For basic help, type Ctrl+G."));
Je modifie le fichier source pour remplacer le message par :
statusbar(_("Welcome to my patched version of nano."));
Je crée un commit pour cette modification en lui donnant un libellé descriptif. Dans un vrai projet on enchaîne souvent une dizaine de commits au fur et à mesure de la mise au point.
[nano]$ git commit src/nano.c -m 'modify welcome message.' [devtool bf4b83b] modify welcome message 1 file changed, 1 insertion(+), 1 deletion(-)
Nous pourrions tester notre modification avant de la commiter. Ici, elle est si simple que je la valide directement. Pour cela je sors du répertoire de travail.
[nano]$ cd ../../../ [build-qemu]$
Et je demande à devtool
d'intégrer
mon commit sous forme de patch dans mon layer.
[build-qemu]$ devtool update-recipe nano -a ../../layers/meta-my-layer/ NOTE: Starting bitbake server... [...] NOTE: Writing append file /home/Builds/Lab/layers/meta-my-layer/recipes-support/nano/nano_7.2.bbappend NOTE: Copying 0001-modify-welcome-message.patch to /home/Builds/Lab/layers/meta-my-layer/recipes-support/nano/nano/0001-modify-welcome-message.patch [build-qemu]$
devtool
a créé :
0001-modify-welcome-message.patch
qu'il a placé dans le sous-répertoire «recipes-support/nano/nano/
» de notre layer.
Le choix de la catégorie «recipes-support
» est dû à l'emplacement
initial de la recette «meta-openembedded/meta-oe/recipes-support/nano/nano_7.2.bb
».
Le fait de placer le patch dans le sous-répertoire «nano/nano/
» est
une habitude avec Yocto : le répertoire accueillant les fichiers complémentaires à une recette
est nommée gnéralement «files/
» ou avec le même nom que la recette.
[build-qemu]$ cat ../../layers/meta-my-layer/recipes-support/nano/nano_7.2.bbappend FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" SRC_URI += "file://0001-modify-welcome-message.patch"
on remarquera que dans la ligne «FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
»
la partie gauche «"${THISDIR}/files:"
» que nous utilisions auparavant a été
remplacée par «"${THISDIR}/${PN}:"
», la variable «${PN}
»
(Package Name) contenant le nom de la recette.
Nous pouvons relancer le build de notre système :
[build-qemu]$ bitbake my-image
Puis sur notre cible virtuelle, nous pouvons admirer le résultat de
notre patch en lançant la commande nano
, comme on
le voit sur la figure II.3-3.
Nous avons vu dans cette séquence comment modifier le comportement de recettes existantes sans toucher aux fichiers originaux, avec différentes approches selon le type de modification à apporter.
Le principe des extensions grâce aux fichiers .bbappend
est très puissant et permet de garantir la pérennité des modifications
que l’on apporte même si les versions des packages d’origine
évoluent.
Les deux premières parties de ce cours en ligne nous ont permis de voir comment créer une image de Linux embarqué pour une architecture cible de notre choix, et d’ajuster son contenu. Il est temps à présent de s’intéresser à l’ajout de notre propre code, ce qui sera l’objet de la troisième partie.
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.