Linux embarqué avec Yocto (étape II.2)


Christophe BLAESS – Juillet 2019

Ajout d’applications dans l’image

Dans la séquence précédente, nous avons modifié le fichier local.conf que nous trouvons dans le sous-répertoire conf/ de notre répertoire de build. Les modifications étaient assez simples : ajustement de l’emplacement des dossiers de stockage temporaire, ajout d’utilisateur et configuration de mots de passe, puis modification du nom de machine. Dans cette séquence nous allons ajouter quelques applications sur notre image.

Utilitaires présents dans Poky

Notre première possibilité est d’ajouter des packages dont les recettes sont déjà livrées avec Poky.

[build-qemu]$ ls ../poky/meta/recipes*
../poky/meta/recipes.txt
../poky/meta/recipes-bsp:
acpid alsa-state apmd formfactor gnu-efi grub keymaps libacpi lrzsz pciutils pm-utils setserial u-boot usbinit usbutils v86d
../poky/meta/recipes-connectivity:
avahi bluez5 dhcp iproute2 iw libpcap neard ofono openssl ppp-dialin socat
bind connman inetutils irda-utils libnss-mdns mobile-broadband-provider-info nfs-utils openssh ppp resolvconf wpa-supplicant
../poky/meta/recipes-core:
base-files console-tools dbus-wait fts glibc images initscripts libxcrypt musl newlib packagegroups sysfsutils udev volatile-binds
base-passwd coreutils dropbear gettext glib-networking init-ifupdown kbd libxml ncurses os-release psplash systemd update-rc.d zlib
busybox dbus expat glib-2.0 ifupdown initrdscripts libcgroup meta netbase ovmf readline sysvinit util-linux
../poky/meta/recipes-devtools:
apt build-compare devel-config dwarfsrcfiles gdb icecc-toolchain llvm mtools patchelf python-numpy strace unifdef
autoconf ccache diffstat e2fsprogs git intltool m4 nasm perl qemu subversion vala
autoconf-archive cdrtools distcc elfutils glide json-c make ninja perl-sanity quilt swig valgrind
automake chrpath dmidecode expect gnu-config libcomps makedevs opkg pkgconf rpm syslinux xmlto
binutils cmake dnf fdisk go libdnf meson opkg-utils pkgconfig rsync systemd-bootchart
bison createrepo-c docbook-xml file help2man libmodulemd mklibs orc prelink ruby tcf-agent
bootchart2 cve-check-tool dosfstools flex i2c-tools librepo mmc packagegroups pseudo run-postinsts tcltk
btrfs-tools desktop-file-utils dpkg gcc icecc-create-env libtool mtd patch python squashfs-tools unfs3
[...]
../poky/meta/recipes-support:
apr boost enchant gpgme libcap-ng libffi libmpc libunwind lzop p11-kit shared-mime-info
argp-standalone ca-certificates fribidi icu libcheck libfm libnl liburcu mpfr pinentry source-highlight
aspell consolekit gdbm iso-codes libcroco libgcrypt libpcre libusb nettle popt sqlite
atk curl gmp libassuan libdaemon libgpg-error libproxy libxslt npth ptest-runner taglib
attr db gnome-desktop-testing libatomic-ops libevdev libical libpsl libyaml nspr re2c user-creation
bash-completion debianutils gnupg libbsd libevent libjitterentropy libsoup lz4 nss rng-tools vim
bmap-tools dos2unix gnutls libcap libexif libksba libunistring lzo nss-myhostname serf vte
[build-qemu]$

La liste n’est pas évidente à lire, mais un comptage rapide avec “find ../poky/meta/recipes* -name '*bb'| wc -l” nous indique la présence de près de 800 recettes livrées dans Poky. La plupart d’entre-elles sont des services ou des utilitaires bas-niveaux assez peu visibles au premier abord. Nous pouvons toutefois ajouter sur notre image un petit outil que j’aime bien : mc le Midnight Commander. Pour cela nous ajoutons simplement la ligne suivante dans local.conf :

IMAGE_INSTALL += "mc"

La syntaxe des recettes est assez précise. L’opérateur += demande à bitbake de rajouter la chaîne indiquée en fin de variable IMAGE_INSTALL en la précédant d’un espace. Comme son nom l’indique, cette variable contient une liste des packages à installer dans l’image produite. Plusieurs lignes de ce type peuvent se suivre pour allonger d’autant le contenu de l’image.

Après avoir regénéré core-image-base et nous être connectés, nous pouvons lancer la commande mc et goûter au parfum un peu suranné des années 1990 sur Ms-Dos (figure II.2-1). Il est important toutefois de comprendre que cet outil peut-être très pratique lors de la mise au point d’un système embarqué pour le confort du développement en ligne de commande.

Figure II.2-1 – Intégration de mc sur core-image-base.

Il existe d’autre outils dont les recettes se trouvent dans Poky que j’aime bien intégrer dans mes images embarquées afin de permettre la mise au point du code métier : strace, valgrind, powertop et gdbserver. Je détaillerai leur utilisation dans la troisième partie, pour l’instant contentons-nous d’ajouter les lignes suivantes :

IMAGE_INSTALL += "mc"
IMAGE_INSTALL += "strace"
IMAGE_INSTALL += "gdbserver powertop"

Comme on le voit, on peut aussi bien enchaîner des lignes d’ajout que regrouper les différents packages désirés dans une seule ligne. Je n’ai pas intégré l’utilitaire valgrind car il n’est pas supporté par la génération de processeur émulé par qemuarm, mais si vous faites un build pour Raspberry Pi par exemple, il vous est tout à fait possible de l’ajouter.

Après recompilation de l’image, je vérifie la présence des outils ajoutés. Je ne m’intéresse pas ici à leur fonctionnement ou leur résultat, juste à leur présence sur ma cible

mybox login: root
Password: (linux)
root@mybox:~# strace -V
strace -- version 4.26
Copyright (c) 1991-2018 The strace developers https://strace.io.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Optional features enabled: (none)
root@mybox:~# gdbserver --version
GNU gdbserver (GDB) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
gdbserver is free software, covered by the GNU General Public License.
This gdbserver was configured as "arm-poky-linux-gnueabi"
root@mybox:~# powertop --version
PowerTOP version v2.10
root@mybox:~#

Ajout de packages hors Poky

Pendant la mise au point d’un système embarqué, on a souvent besoin d’éditer des fichiers directement sur la cible. Sur une installation core-image-base, nous disposons bien de l’éditeur vi, intégré dans le package busybox. Néanmoins tout le monde n’est pas familier des commandes de vi, et l’utilisation d’un éditeur un peu plus intuitif s’avère généralement plus reposante. Supposons que nous souhaitions installer nano par exemple, qui est plus simple d’emploi que vi.

Si nous essayons simplement d’ajouter la ligne

IMAGE_INSTALL += "nano"

dans notre fichier local.conf, bitbake va se plaindre, nous afficher une série de lignes en rouge et terminer en indiquant une erreur :

NOTE: Resolving any missing task queue dependencies
ERROR: Nothing RPROVIDES 'nano' (but /home/cpb/Yocto-lab/poky/meta/recipes-core/images/core-image-base.bb RDEPENDS on or otherwise requires it)
NOTE: Runtime target 'nano' is unbuildable, removing…
Missing or unbuildable dependency chain was: ['nano']
ERROR: Required build target 'core-image-base' has no buildable providers.
Missing or unbuildable dependency chain was: ['core-image-base', 'nano']
Summary: There were 2 ERROR messages shown, returning a non-zero exit code.

Clairement, bitbake n’a pas trouvé dans les recettes fournies par Poky celle permettant de construire nano.

Il va probablement nous falloir trouver un layer (un ensemble de recettes) à installer sur notre système. Pour cela, l’usage est de se rendre sur le site https://layers.openembedded.org, de cliquer sur l’onglet recipes et de saisir le nom du package désiré dans le moteur de recherche. Nous trouvons alors une page de résultat comme celle de la figure II.2-2.

Figure II.2-2 – Recherche sur le site Open Embedded Layers Index

Clairement la recette qui m’intéresse est la première de la liste. Elle se trouve dans le layer indiqué dans la colonne de droite : meta-oe. En cliquant sur ce lien je vois qu’il s’agit d’un layer appartenant à un ensemble plus grand : meta-openembedded, et je trouve l’adresse du téléchargement à effectuer.

[build-qemu]$ cd ..
[Yocto-lab]$ git clone git://git.openembedded.org/meta-openembedded
Clonage dans 'meta-openembedded'…
remote: Counting objects: 107398, done.
remote: Compressing objects: 100% (36934/36934), done.
[...]
Résolution des deltas: 100% (66217/66217), fait.
[Yocto-lab]$ ls meta-openembedded/
contrib meta-gnome meta-networking meta-python README
COPYING.MIT meta-initramfs meta-oe meta-webserver
meta-filesystems meta-multimedia meta-perl meta-xfce
[Yocto-lab]$

L’ensemble meta-openembedded est assez incontournable dès lors que l’on prépare un système avec Yocto. Il contient plus d’un millier de recettes pour de nombreux packages très utiles pour Linux embarqué

Nous devons ajouter le layer meta-oe à la liste de ceux pris en compte dans notre build.

[Yocto-lab]$ cd build-qemu/
[build-qemu]$ bitbake-layers add-layer ../meta-openembedded/meta-oe/
NOTE: Starting bitbake server…
[build-qemu]$

Nous pouvons à présent relancer notre compilation, elle se déroule normalement et nano est intégré dans notre image.

[build-qemu]$ bitbake  core-image-base
[...]
Figure II.2-3 – L’éditeur nano sur notre cible.

Utilisation des fonctionnalités d’image

Nous avons utilisé la compilation avec core-image-base un peu aveuglément, sans comprendre véritablement ce que cela signifie. Nous allons examiner son contenu plus en détail. Pour cela nous recherchons le fichier qui décrit core-image-base dans les répertoires de Poky. Il s’agit d’une recette avec l’extension .bb.

[build-qemu]$ find  ../poky/  -name  core-image-base.bb
../poky/meta/recipes-core/images/core-image-base.bb

L’emplacement du fichier est parfaitement logique. Voyons son contenu.

[build-qemu]$ cat ../poky/meta/recipes-core/images/core-image-base.bb 
SUMMARY = "A console-only image that fully supports the target device \
hardware."
IMAGE_FEATURES += "splash"
LICENSE = "MIT"
inherit core-image

Hormis la description et la licence, deux lignes nous intéressent :

  • inherit core-image : la recette hérite d’une classe prédéfinie qui décrit le contenu d’une image en proposant des fonctionnalités optionnelles.
  • IMAGE_FEATURES += "splash" ajoute la fonctionnalité splashscreen à notre image. Dans la définition de la classe core-image, une ligne contenant en substance FEATURE_PACKAGES_splash = "psplash" indique quel package doit être ajouté pour répondre à cette fonctionnalité.

Nous voyons que Yocto nous propose ainsi ce mécanisme de features, des fonctionnalités de haut niveau que l’on peut sélectionner sans se soucier du détail du package correspondant.

Voici les fonctionnalités proposées par la classe core-image.

x11Serveur X-window
x11-baseServeur X-window et environnement minimal (Matchbox)
x11-satoServeur X-window et environnement Sato pour mobile.
tools-debugOutils de débogage (gdb, gdbserver, strace, gcore…)
eclipse-debugOutils de débogage distant avec Eclipse.
tools-profileOutils de profiling (perf, lttng, grpof…)
tools-testappsOutils de tests du matériel.
tools-sdkInstallation des outils de développement natifs (gcc, make…) sur la cible.
nfs-serverServeur NFS
nfs-clientClient NFS
ssh-server-dropbearServeur SSH basé sur Dropbear.
ssh-server-opensshServeur SSH basé sur Openssh
hwcodecsSupport des codecs pour l’accélération matérielle
package-managementSupport des packages sur la cible (installation des outils et base de données).
dev-pkgsInstallation des fichiers headers nécessaire pour le développement des packages présents.
dbg-pkgsTous les packages sont compilés avec les informations de débogage
doc-pkgsInstallation de la documentation associée à tous les packages
read-only-rootfsSystème de fichiers en lecture-seule.
splashÉcran d’accueil pendant le boot

Nous pouvons, par exemple, ajouter dans notre fichier local.conf la ligne

IMAGE_FEATURES += "tools-sdk"

pour tester la présence des outils de compilation sur la cible.

mybox login: root
Password: (linux)
root@mybox:~# vi my-hello.c
#include <stdio.h>
#include <unistd.h>

int main(void)
{
char host[512];
gethostname(host, 512);
printf("Hello from %s\n", host);
return 0;
}
root@mybox:~# gcc my-hello.c -o my-hello -Wall
root@mybox:~# ./my-hello
Hello from mybox
root@mybox:~# g++ --version
g++ (GCC) 8.3.0
[...]
root@mybox:~#

Il n’est pas fréquent d’installer une chaîne de compilation native directement sur la plateforme cible, mais cela peut s’avérer intéressant pendant la phase de prototypage et de mise au point. Il s’agit d’un point sur lequel Yocto est plus puissant que son confrère Buildroot qui a renoncé à cette possibilité il y a quelques années.

Création d’une image spécifique

Jusqu’à présent nous avons utilisé l’image core-image-base en ajoutant dans local.conf des lignes “IMAGES_INSTALL_append“. Cette approche est parfaitement adaptée pour les premières phases de configuration du système, mais trouve rapidement ses limites. Pour les systèmes industriels en effet, il est souvent nécessaire de gérer tout une gamme de produits différents. On est donc amenés à réaliser régulièrement des séries de builds avec peu de différences entre-eux. On préfère généralement factoriser toute la configuration commune aux différents produits dans une image particulière et ne laisser dans les fichiers local.conf que les spécificités propres à chaque build.

Autrement dit nous allons créer notre propre fichier de description d’image, et nous n’invoquerons plus “bitbake core-image-base” mais “bitbake my-own-image” par exemple (en situation réelle, je nomme plutôt l’image en fonction de mon client ou de son projet).

Pour cela, nous devons commencer par créer notre propre layer. Rien de compliqué, l’outil bitbake-layers est là pour nous aider.

[build-qemu]$ bitbake-layers  create-layer  ../meta-my-own-layer
NOTE: Starting bitbake server…
Add your new layer with 'bitbake-layers add-layer ../meta-my-own-layer'
[build-qemu]$ ls ..
build-bbb build-qemu build-rpi downloads meta-my-own-layer meta-openembedded meta-raspberrypi poky sstate-cache
[build-qemu]$

Le layer est bien créé mais, comme bitbake-layers nous l’affiche de manière un peu ambiguë, il n’est pas encore intégré dans la liste des layers que nous utilisons pour nos builds. Nous devons l’y ajouter.

[build-qemu]$ bitbake-layers  show-layers
NOTE: Starting bitbake server…
layer path priority
meta /media/cpb/USB-EXT/Labo/Yocto-lab/poky/meta 5
meta-poky /media/cpb/USB-EXT/Labo/Yocto-lab/poky/meta-poky 5
meta-yocto-bsp /media/cpb/USB-EXT/Labo/Yocto-lab/poky/meta-yocto-bsp 5
meta-oe /media/cpb/USB-EXT/Labo/Yocto-lab/meta-openembedded/meta-oe 6
[build-qemu]$ bitbake-layers add-layer ../meta-my-own-layer/
NOTE: Starting bitbake server…
[build-qemu]$ bitbake-layers show-layers
NOTE: Starting bitbake server…
layer path priority
meta /media/cpb/USB-EXT/Labo/Yocto-lab/poky/meta 5
meta-poky /media/cpb/USB-EXT/Labo/Yocto-lab/poky/meta-poky 5
meta-yocto-bsp /media/cpb/USB-EXT/Labo/Yocto-lab/poky/meta-yocto-bsp 5
meta-oe /media/cpb/USB-EXT/Labo/Yocto-lab/meta-openembedded/meta-oe 6
meta-my-own-layer /media/cpb/USB-EXT/Labo/Yocto-lab/meta-my-own-layer 6
[build-qemu]$

Nous créons une petite arborescence et copions le fichier core-image-base.bb pour avoir un point de départ.

[build-qemu]$ mkdir -p  ../meta-my-own-layer/recipes-custom/images/
[build-qemu]$ cp ../poky/meta/recipes-core/images/core-image-base.bb ../meta-my-own-layer/recipes-custom/images/my-own-image.bb

Éditons le fichier my-own-image.bb, pour obtenir par exemple :

SUMMARY = "A customized image for development purposes."
LICENSE = "MIT"
inherit core-image
IMAGE_FEATURES += "splash"
IMAGE_FEATURES += "tools-debug"
IMAGE_FEATURES += "tools-profile"
IMAGE_FEATURES += "tools-sdk"
IMAGE_FEATURES += "ssh-server-dropbear"
IMAGE_INSTALL += "mc"
IMAGE_INSTALL += "nano"

Nous éditons local.conf pour supprimer toutes les lignes IMAGE_INSTALL_append et IMAGE_FEATURES que nous avions ajoutées auparavant et lançons le nouveau build avec :

[build-qemu]$ bitbake  my-own-image

Conclusion

Nous avons vu dans cette séquence – assez longue – comment personnaliser notre image en ajoutant des applications dont les recettes sont livrées avec Poky ou référencées sur le site Open Embedded Layers Index. Nous avons également réussi à créer notre propre image, plutôt que de se limiter à enrichir core-image-base.

Dans la prochaine séquence, nous verrons comment modifier le comportement d’une application existante, sans toucher aux recettes téléchargées…