Linux Embarque
Linux Embarque
Linux Embarque
Utilisation de Yocto 19
Construction d’une image Yocto 20
Fonctionnement et configuration 27
Notion de recette (.bb) 28
Notion de classe (.bbclass) 29
Fichier à inclure (.inc) 29
Utilisation de BitBake 29
Prise en charge des paquets 30
Création de recettes 33
Ajout d’une recette simple 34
Recette d’image 38
4
Extension de recette (fichier .bbappend) 39
Modification d’une recette 39
Principe du .bbappend 40
Cas d’utilisation du .bbappend 41
Utilisation de Devtool 42
Production du SDK 44
Utilisation du compilateur 45
Intégration continue 46
Test de paquet (ptest) 46
Test d’une image (testimage) 50
Conclusion 54
Bibliographie 55
5
A propos de Smile
Nous sommes plus de +1800 passionnés travaillant sur des solutions
digitales créatives et innovantes, dans plus de 7 pays.
Notre approche est basée sur la compréhension des spécificités de votre
marché, de votre business, de vos enjeux financiers et de vos défis présents
et à venir.
Notre ADN open source est la garantie de notre proposition de valeur. Dans
un souci constant de neutralité vis-à-vis de nos partenaires, nous proposons
toujours la solution la plus adaptée à vos objectifs business et votre
organisation.
Visionnaires, formés et certifiés, les Smiliens s’engagent pour faire grandir les
projets que vous nous confiez, avec toute l’audace, la technicité et
l’innovation qui nous caractérisent.
6
A propos de ce livre blanc
Le livre blanc consacré à l'utilisation de Linux dans les systèmes industriels et
embarqués fut le premier de la série en 2016. Ce livre constitue une mise à
jour importante et se focalise sur Yocto et non plus sur Buildroot.
Après un bref historique et quelques rappels sur les principes d'un système
embarqué (matériel et logiciel) nous décrirons les éléments fondamentaux
constituant une distribution Linux.
Nous continuerons par la définition d’un système « Linux embarqué » puis
l’introduction à la notion de « build system » (outil de construction de
distribution). La suite du livre sera consacrée à l'étude de l’outil Yocto, qui est
désormais le plus répandu dans le monde industriel pour la mise en place de
systèmes embarqués basés sur Linux.
7
Introduction aux systèmes embarqués
Par définition, un système embarqué est l'association de matériel (un
calculateur) et de logiciel. Contrairement à l'informatique classique (poste de
travail ou serveur), le système est dédié à un ensemble fini de fonctionnalités
et il en est de même pour le logiciel.
Les premiers domaines d'application étaient limités à l'armement et au spatial
pour lesquels les coûts des programmes étaient très élevés. La principale
difficulté à l'époque était l'absence de processeur car le 4004 - premier
microprocesseur disponible commercialement - fut créé par Intel (seulement)
en 1971. Dans le domaine spatial, on s'accorde à dire que le premier système
embarqué fut l'« Apollo Guidance Computer » [1] créé en 1967 par le MIT
pour le programme spatial Apollo. Ce dernier disposait de 36 Kmots de ROM,
2 Kmots de RAM et fonctionnait à la fréquence de 2 MHz. De nos jours, on
peut simuler le comportement de ce calculateur grâce à une page web
animée par du code Javascript ! Dans le cas des applications militaires, on
peut citer le calculateur D-17B, système de guidage pour le missile LGM-30
datant du début des années 60 [2].
Il n'était pas question à l'époque d'évoquer la notion de système
d'exploitation embarqué et on parlait simplement de logiciel embarqué
souvent écrit en langage machine. Par contre, le programme Apollo utilisait
de nombreux calculateurs IBM/360 au sol et le logiciel le plus complexe de la
mission occupait 6 Mo. Sur cet IBM/360, la NASA utilisait une version
modifiée de l'OS/360 nommée RTOS/360 [3], afin de disposer d’un
comportement temps réel.
REMARQUE
Même si on utilise désormais des langages évolués comme C ou Ada,
certains systèmes embarqués sont toujours dépourvus d'OS. On parle alors
de système « bare metal ».
8
fonctionnent sur des processeurs du commerce, la plupart étant
commercialisés par des éditeurs spécialisés. Nous pouvons citer VRTX (1981)
édité par Mentor Graphics (désormais SIEMENS) et célèbre pour être utilisé
dans le télescope Hubble, VxWorks (1987) édité par Wind River et LynxOS
(1986) édité par Lynx Software. VxWorks est toujours très utilisé dans les
industries sensibles comme le spatial. Il fut entre autre choisi pour la sonde
spatiale Pathfinder (1996) ainsi que pour la mission Curiosity lancée en 2011
et toujours active. Dans le domaine du logiciel libre, le système d’exploitation
RTEMS est également fréquemment choisi par la NASA ou l'agence spatiale
européenne (ESA). Ce système diffusé sous licence GPL modifiée est utilisé
pour le système de communication du rover Curiosity et de nombreuses
autres missions. Il est également utilisé dans les satellites développés par
Airbus Defense and Space.
A partir des années 2000, les systèmes embarqués ne se limitent plus aux
applications industrielles ni donc aux RTOS ce qui permet de choisir un
système comme Linux (qui par défaut n'a pas de capacités temps réel). Linux
est désormais présent dans 95 % des boîtiers d'accès à Internet, décodeur
TV, sans compter le fameux système Android qui intègre un noyau Linux. Plus
récemment, des alliances d'acteurs de l'industrie automobile ont permis la
mise en place de projets comme GENIVI ou AGL (basés sur Yocto) dont le but
est de créer des environnements utilisables pour les applications IVI (pour In
Vehicle Infotainment).
9
nommé MULTICS [5]. Ce dernier - créé en 1964 au MIT - était surtout adapté
aux gros systèmes. La programmation de MULTICS utilisait un langage
proche du langage C créé par IBM sous le nom de PL/1 (pour Programming
Language number 1). L'équipe de recherche d'AT&T avait pour but de créer
un nouveau langage (le langage C) ainsi qu'un système d'exploitation
reprenant les concepts de MULTICS mais pouvant fonctionner sur des
mini-ordinateurs de l'époque, soit des machines très peu puissantes. En
hommage à son prédécesseur, le système fut nommé UNICS puis UNIX. En
France, l'un des premiers calculateur pouvant fonctionner sous UNIX fut le
SM-90 [6] (équipé d'un CPU Motorola 68000 et de 512 Ko de RAM). De
conception française, la machine fut rapidement évincée par les stations de
travail d'origine américaine (en premier lieu SUN puis IBM, HP, Silicon
Graphics, etc.) utilisant leurs propres versions d'UNIX (SunOS puis Solaris,
AIX, HP/UX, ou IRIX).
De par la faible puissance des machines à l'époque de sa conception,
l'architecture UNIX est assez simple.
10
REMARQUE
Le proverbe UNIX le plus célèbre est certainement :
« Sous UNIX tout est fichier sauf les processus ».
Même si le noyau Linux fut créé au début des années 90 (soit 20 ans plus
tard), l'architecture choisie est quasiment identique ce qui valut à Linus
Torvalds les reproches d'Andrew Tannenbaum, grand spécialiste du système
UNIX et auteur de MINIX, une version d'UNIX utilisée par Linus Torvalds pour
construire son premier système. Selon le vénérable Professeur Tannenbaum,
Linus aurait manqué d'audace en créant un nième système UNIX
monolithique (fonctionnant avec un seul noyau fournissant l’ensemble des
services).
Distribution Linux
La plupart des utilisateurs s’orientent vers l’utilisation d'une distribution qui
correspond à un ensemble de composants logiciels que l'on peut installer sur
un calculateur grâce à une procédure la plus simple possible. Les plus
célèbres distributions sont Debian, Ubuntu, Fedora ou bien RHEL (dans le
monde professionnel). Au fur et à mesure de l'histoire de Linux (projet
démarré, rappelons le en 1991), la procédure d'installation s'est
considérablement simplifiée passant de la compilation manuelle de dizaines
de composants (le noyau Linux et les divers utilitaires du projet GNU qui
constituent la partie visible du système) jusqu'à une procédure quasiment
automatique qui n'a rien à envier aux systèmes d'exploitation commerciaux
tels que Windows ou MacOS X.
11
Cette simplicité idyllique concerne cependant les serveurs et PC de bureau
basés sur l’architecture x86. Dans ce cas, l'espace disque est quasiment
illimité (difficile de nos jours de trouver un disque dur de capacité inférieure à
500 Go) par rapport à l'espace occupé par la distribution (quelques Go voire
plus). De ce fait, la procédure prend l'initiative d'installer de nombreux
composants parfois inutiles qui eux-même dépendent d'autres composants.
Si on prend l'exemple d'une distribution Ubuntu récente, on note assez
rapidement qu’un système minimal est composé au bas mot de près de 2000
composants (ou « paquets »).
En effet, qui aurait cru il y a plus de 20 ans – à l'époque du Nokia 3210 - que
la quasi-totalité des smartphones seraient finalement basés sur un noyau
Linux (cas d'Android) ou d’une architecture proche d'UNIX (cas des systèmes
Android et iOS).
12
Architecture « Linux embarqué »
Comme dans le cas d’une distribution Linux classique, une distribution “Linux
embarqué” est composée de deux éléments principaux :
1. Le noyau Linux
2. Le root-filesystem
13
d’exemple, la commande bash présente dans tous les systèmes Linux
occupe le même espace (environ 1 Mo) que l’exécutable busybox qui
remplace environ 300 commandes Linux (bien entendu dans des versions
allégées en fonctionnalités). Nous décrirons plus en détail BusyBox un peu
plus loin dans ce livre.
Le compilateur est bien entendu un élément fondamental pour la création du
système. En effet, la cible choisie utilise le plus souvent une architecture
différente de celle du poste de développement ce qui nécessite l'installation
d'un compilateur dit « croisé » (exemple, x86 vers ARM). Certaines
distributions comme Ubuntu intègrent directement les paquets nécessaires.
Cependant il est également possible (et recommandé) d'obtenir des chaînes
de compilation auprès de Linaro, ARM ou bien SIEMENS (Sourcery
CodeBench). De nos jours, les outils de construction ou « build system »
(Yocto, Buildroot) que nous verrons plus tard peuvent également produire un
compilateur croisé à partir des sources.
L'outil BusyBox
Le projet BusyBox a démarré en 1995 sous l'impulsion de Bruce Perens,
membre du projet Debian. Le but était de produire une disquette de
réparation pour la distribution Debian et rappelons que l'espace disponible
sur un tel support n'était que de 1,44 Mo. BusyBox rassemble donc les outils
courants d'une distribution Linux (shell, éditeurs, commandes de
manipulation de fichiers, etc.) dans un exécutable unique nommé busybox.
Bien entendu les fonctionnalités de chaque commande sont largement
inférieures à celles des versions originales du projet GNU mais comme nous
l'avons dit ce point n'est pas un problème pour un système embarqué. Le
principe de BusyBox étant d'intégrer toutes les commandes dans un seul
exécutable, on place un lien symbolique correspondant au nom de la
commande (sh, ls, vi, etc.) ce qui permet d'exécuter la bonne portion de code
(et d’optimiser l’empreinte mémoire utilisée).
$ ls -l bin/sh bin/busybox
-rwxr-xr-x 1 pierre pierre 968032 oct. 13 16:03
bin/busybox
14
lrwxrwxrwx 1 pierre pierre 7 oct. 13 16:03 bin/sh ->
busybox
$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1113504 juin 7 2019 /bin/bash
15
Bionic (spécifique à Google). Dans le cas de Yocto ou Buildroot, on produit en
général la chaîne de compilation à partir des sources (donc en précisant le
type de libc). Ces outils permettent également d’utiliser une chaîne binaire et
dans ce cas, le type de libc est bien entendu imposé par la chaîne.
16
x86 (même s’il y a des exceptions comme la Raspbian, désormais Raspberry
Pi OS).
La solution du « build system » est la principale évoquée dans ce livre mais
elle n’a bien entendu pas que des avantages (bien qu’étant la plus répandue).
En effet, des solutions basées sur l’écosystème Debian (soit ELBE [7] et
DEBOS [8]) sont également possibles et ont l’avantage de s’appuyer sur un
projet célèbre pour la qualité de sa production.
« It's not an embedded Linux distribution – it creates a custom one for you. »
17
● Un « moteur de construction » permettant de réaliser les différentes
étapes de chaque recette (télécharger, extraire, configurer, compiler,
installer, etc.). On parle souvent du « cuisinier qui utilise des
recettes » et cette analogie est très réaliste. Le moteur se charge
également d'intégrer les différents composants binaires dans l'image
finale à installer sur la cible.
REMARQUE
Un outil de build system n'est pas destiné au développement mais à
l'intégration des composants (standards ou ajoutés). Il permet à l'utilisateur de
se focaliser sur la valeur ajoutée de son produit (i.e. ses applications), la
gestion de composants génériques étant prise en compte par l'outil. Par
contre, il permet de créer les composants nécessaires à un environnement de
développement croisé (dont le compilateur croisé inclus dans le SDK).
18
donc pas comme Yocto d’un financement de la part de la fondation Linux.
OpenWrt est dérivé de Buildroot. Il fut initialement développé pour le routeur
Linksys WRT54GL (d’où le nom) mais fonctionne désormais sur près de 1800
modèles de routeurs. Contrairement à Buildroot, il inclut la notion de paquet
binaire. OpenWrt a été officiellement utilisé pour la box de SFR ainsi que le
routeur Fonera de la communauté FON.
D'autres outils similaires sont également diffusés sous licence libre (PTXdist,
LTIB, etc.) mais leur utilisation est plus confidentielle. Les principes utilisés
sont cependant les mêmes.
Utilisation de Yocto
Yocto est basé sur deux composants, soit OpenEmbedded (OE) et BitBake.
Ils furent créés suite à des limitations constatées sur les fonctionnalités de
Buildroot dans le cadre du projet OpenZaurus (mais c'était vers 2003 !). En
2010, EO et BitBake – ainsi que d'autres projets affiliés – furent rassemblés
dans un projet « chapeau » nommé Yocto. A ce jour, Yocto est l’outil le plus
fréquemment utilisé pour la construction d’un BSP. Les sources sont
disponibles auprès du projet Yocto (et/ou de GitHub) [9] ou bien sur le dépôt
du fabricant (cas de Toradex [10]).
REMARQUE
yocto (symbole y) est le préfixe du système international d'unités qui
représente 10-24 fois cette unité (soit un quadrillionième). Adopté en 1991, il
vient du grec ὀκτώ, (huit) car égal à (10-3)8 .
19
support d'un composant matériel donné, mais également des
composants logiciels. Les couches sont représentées par des
« métadonnées » rassemblées dans des répertoires
(meta-raspberrypi, meta-qt, meta-ivi, etc.).
● Du fait du principe précédent, Yocto fournit un environnement initial
très léger (basé sur OE) qui permet de produire une distribution pour
quelques cibles de référence (souvent émulées par QEMU). Le
support de matériel réel est disponible à l'extérieur du projet sous
forme de layers fournissant le BSP.
● Grâce à BitBake, Yocto peut paralléliser les actions. Il peut
télécharger les sources d'un composant A tout en compilant le
composant B et créer le paquet pour le composant C.
● Yocto permet d'utiliser plusieurs environnements de compilation
(pour plusieurs cibles) dans le même répertoire de travail.
● Yocto ne dispose pas (réellement) d'un outil de configuration
graphique similaire à make menuconfig et la configuration s'effectue
dans des fichiers. L'outil Toaster fourni avec Yocto reste très peu
utilisé car très limité.
20
REMARQUE
Mise à part la production d’une image simple pour la Raspberry Pi 3, la
majorité des manipulations seront réalisées sur QEMU afin que le lecteur
puisse les reproduire plus facilement sans disposer de matériel. Les
fonctionnalités démontrées dans le livre sont indépendantes de la cible
matérielle utilisée.
Nous choisissons la version 3.1 de Yocto nommée « Dunfell » car c’est une
version dite LTS (pour Long Term Support) utilisée par de nombreux
fabricants. Les principes exposés restent valables pour les autres versions, la
dernière version étant la 3.3 au moment de la rédaction du livre. En premier
lieu, on doit tout d'abord obtenir les sources par la commande suivante qui
crée le répertoire poky (nom de la distribution d'exemple de Yocto).
$ cd poky
$ source oe-init-build-env qemuarm-build
...
### Shell environment set up for builds. ###
21
You can also run generated qemu images with a command like
'runqemu qemuarm'
REMARQUE
La commande UNIX source exécute un script dans l'environnement du shell
courant, et non du shell fils, ce qui permet d'affecter des variables
d'environnement dans le shell courant (et donc de les conserver).
MACHINE = "qemuarm"
22
entre les tâches à réaliser, bitbake exécute en parallèle plusieurs actions,
correspondant au maximum au nombre de cœurs présents dans la machine
de compilation.
$ bitbake core-image-minimal
Parsing recipes: 100%
|###############################################################
################################################################
#######################################| Time: 0:00:15
Parsing of 774 .bb files complete (0 cached, 774 parsed). 1326
targets, 61 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
Build Configuration:
BB_VERSION = "1.46.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "ubuntu-18.04"
TARGET_SYS = "arm-poky-linux-gnueabi"
MACHINE = "qemuarm"
DISTRO = "poky"
DISTRO_VERSION = "3.1.6"
TUNE_FEATURES = "arm armv7ve vfp thumb neon
callconvention-hard"
TARGET_FPU = "hard"
meta
meta-poky
meta-yocto-bsp =
"dunfell:1cb03844e124b88b98ddfdd4fce47fb545c6fe5e"
23
3: openssl-native-1.1.1j-r0 do_compile - 1s (pid 17316)
4: libx11-1_1.6.9-r0 do_unpack - 0s (pid 18070)
5: base-files-3.0.14-r89 do_unpack - 0s (pid 18573)
6: expat-2.2.9-r0 do_unpack - 0s (pid 18624)
7: unzip-native-1_6.0-r5 do_compile - 0s (pid 18634)
8: xorgproto-native-2019.2-r0 do_patch - 0s (pid 18698)
9: shadow-native-4.8.1-r0 do_unpack - 0s (pid 18791)
...
$ runqemu nographic
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.4.103-yocto-standard
(oe-user@oe-host) (gcc version 9.3.0 (GCC)) #1 SMP PREEMPT
Tue Mar 9 04:13:07 UTC 2021
[ 0.000000] CPU: ARMv7 Processor [412fc0f1] revision 1
(ARMv7), cr=30c5387d
[ 0.000000] CPU: div instructions available: patching
division code
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache,
PIPT instruction cache
[ 3.815173] async_tx: api initialized (async)
[ 3.815501] Block layer SCSI generic (bsg) driver
version 0.4 loaded (major 252)
[ 3.815696] io scheduler mq-deadline registered
[ 3.815820] io scheduler kyber registered
[ 3.817103] pci-host-generic 3f000000.pcie: host bridge
/pcie@10000000 ranges:
...
[ 5.043936] udevd[128]: starting version 3.2.9
[ 5.105136] udevd[129]: starting eudev-3.2.9
[ 6.752997] EXT4-fs (vda): re-mounted. Opts: (null)
[ 6.753416] ext4 filesystem being remounted at /
supports timestamps until 2038 (0x7fffffff)
24
Poky (Yocto Project Reference Distro) 3.1.6 qemuarm
/dev/ttyAMA0
Le test sur une Raspberry Pi 3 (ou toute autre plate-forme réelle) nécessite
l'ajout du BSP qui dans notre cas correspond au répertoire
meta-raspberrypi. On note qu’il est nécessaire d'utiliser la branche
correspondant à la version de Yocto.
$ cd poky
$ git clone -b dunfell
git://git.yoctoproject.org/meta-raspberrypi
$ source oe-init-build-env rpi3-build
MACHINE = "raspberrypi3"
25
comme suit (ajout d’une ligne).
BBLAYERS ?= " \
<path>/poky/meta \
<path>/poky/meta-yocto \
<path>/poky/meta-yocto-bsp \
<path>/poky/meta-raspberrypi \
"
REMARQUE :
Il est important de préciser que le layer peut être placé ailleurs que dans le
répertoire des sources de Yocto.
Même si la cible est très différente de celle du test précédent, la plupart des
sources sont communes aux deux architectures. On peut donc utiliser un lien
symbolique afin d'éviter de télécharger de nouveau l'intégralité des sources.
$ ln -s ../qemuarm-build/downloads .
Une autre option permet de limiter de manière drastique l'espace utilisé pour
la compilation. Pour cela il suffit d'ajouter l'option suivante à la fin du fichier
local.conf.
INHERIT += "rm_work"
Une fois cette option activée, la plupart des fichiers temporaires créés dans
tmp/work seront supprimés au fur et à mesure de la compilation.
Cette option permet donc d'économiser plusieurs dizaines de Go d'espace
disque. A partir de là on peut produire l’image en utilisant de nouveau la
commande bitbake core-image-minimal.
A la fin de la compilation, une image est produite dans
tmp/deploy/images/raspberrypi3.
26
$ umount /dev/mmcblk0p*
$ sudo dd
if=tmp/deploy/images/raspberrypi3/core-image-minimal-
raspberrypi3.wic of=/dev/mmcblk0 status=progress
Fonctionnement et configuration
Après ce test rapide, nous allons détailler un peu plus le fonctionnement de
Yocto (en fait OpenEmbedded et BitBake). La figure suivante décrit le
mécanisme global.
27
Fonctionnement de Yocto
$ bitbake ma-recette
Pour que la recette soit utilisable, il faut bien entendu que le répertoire de
métadonnées qui la contient soit déclaré dans le fichier bblayers.conf.
28
Notion de classe (.bbclass)
Les recettes partagent des procédures communes, par exemple « comment
compiler un composant basé sur Autotools ». De ce fait, Yocto fournit un
certain nombre de classes (fichiers .class) dans le répertoire
meta/classes. On peut bien entendu créer ses propres classes dans des
répertoires de métadonnées ajoutés. L'utilisation d'une classe implique la
présence de la commande inherit dans le fichier .bb.
inherit autotools
On peut également hériter « globalement » d'une classe (i.e. pour toutes les
recettes) en utilisant la variable INHERIT dans le fichier local.conf.
INHERIT += "rm_work"
require linux.inc
include ../common/firmware.inc
include conf/distro/include/security_flags.conf
Utilisation de BitBake
Pour l'instant nous avons utilisé la commande bitbake sans aucun
paramètre mis à part le nom de la recette à produire. La production d'un
paquet binaire correspond à l'exécution de plusieurs étapes (fetch, unpack,
patch, licence, configure, compile, install, package, deploy, etc.). Ces étapes
correspondent à des fonctions do_fetch(), do_unpack(), etc.
Il est parfois utile d'exécuter seulement une étape en utilisant l'option -c, par
exemple :
29
$ bitbake -c fetch ma-recette
REMARQUE
Une méthode utilisable sous Yocto consiste à réaliser des tests en modifiant
local.conf puis à définir une nouvelle recette d’image dérivée d'une
recette fournie par Yocto (voir plus loin dans le document).
Le format de paquet utilisé par défaut dans Yocto est RPM (créé par Red
Hat). Mais on peut également utiliser DEB ou IPK. Ce dernier format fut créé
30
spécifiquement pour les systèmes embarqués à l’époque du projet
OpenEmbedded et il consomme de ce fait beaucoup moins d'espace (quatre
fois moins que le format RPM). Les lignes suivantes ajoutées à local.conf
permettent d’ajouter à la cible le support des paquets IPK.
PACKAGE_CLASSES = "package_ipk"
EXTRA_IMAGE_FEATURES += "package-management"
31
$ bitbake package-index
On doit ensuite ouvrir un accès HTTP sur les répertoires contenant les
paquets. Dans le cas d’un test, on peut utiliser Python qui utilise le port 8000.
$ cd tmp/deploy/ipk
$ python -m SimpleHTTPServer
A partir de là, on peut mettre à jour la base de données sur la cible puis
manipuler les paquets en utilisant la commande opkg. On note que
seulement 36 paquets sont installés sur la cible.
32
Updated source 'armv7vet2hf-neon'.
Downloading http://192.168.7.1:8000/qemuarm/Packages.gz.
Updated source 'qemuarm'.
root@qemuarm:~# df -h
Filesystem Size Used Available Use%
Mounted on
/dev/root 18.3M 9.7M 7.2M 57% /
Création de recettes
Pour l'instant nous avons utilisé les recettes fournies par Yocto ou bien des
recettes annexes comme le contenu de meta-raspberrypi. Nous allons
désormais aborder la création de recette dans le cas d'exemples simples de
type « Hello World ». Les recettes doivent être placées dans des layers
externes car il n'est pas conseillé de modifier les layers existants. La
commande bitbake-layers nous permet de créer un layer de test
meta-example-lb ainsi qu'un exemple de recette (ne contenant aucun
code) dans le répertoire des sources de Yocto.
$ cd poky
$ source oe-init-build-env qemuarm-build
$ bitbake-layers create-layer ../meta-example-lb
NOTE: Starting bitbake server...
Add your new layer with 'bitbake-layers add-layer
../meta-example-lb'
33
de nouveau la commande bitbake-layers.
$ bitbake example
...
NOTE: Executing Tasks
***********************************************
* *
* Example recipe created by bitbake-layers *
* *
***********************************************
NOTE: Tasks Summary: Attempted 675 tasks of which 657 didn't
need to be rerun and all succeeded.
Une recette réelle correspond à un répertoire (soir fahr dans notre cas) et
contenant un fichier de recette fahr_2.0.bb. La version de la recette peut
être codée dans le nom du fichier ou bien définie dans le fichier .bb par la
variable PV.
Le répertoire de la recette peut également contenir un sous-répertoire
fournissant d’autres données pour la compilation de la recette. Le nom du
sous-répertoire correspond le plus souvent au nom du fichier de recette (avec
34
ou sans la version) ou à files . L’exemple ci-dessous correspond à la
recette expat fournie avec Yocto car notre recette n’utilise pas - pour l’instant
- de sous-répertoire.
expat/
├── expat
│ ├── 0001-Add-output-of-tests-result.patch
│ ├── libtool-tag.patch
│ └── run-ptest
└── expat_2.2.10.bb
# Package Revision
PR = "r0"
SRC_URI = "http://pficheux.free.fr/pub/tmp/fahr-2.0.tar.gz"
35
inherit cmake
SRC_URI[md5sum] = "8cd41891470ea0e909181d3a1ec6d47e"
$ bitbake fahr
$ dpkg -c
tmp/deploy/ipk/armv7vet2hf-neon/fahr_2.0-r0_armv7vet2hf-neo
n.ipk
drwxr-xr-x root/root 0 2020-01-27 14:10 ./usr/
drwxr-xr-x root/root 0 2020-01-27 14:10 ./usr/bin/
-rwxr-xr-x root/root 5508 2020-01-27 14:10
./usr/bin/fahr
$ bitbake package-index
36
et2hf-neon.ipk.
Configuring fahr.
root@qemuarm:~# fahr 20
68
$ bitbake core-image-minimal
$ runqemu nographic
...
[ 4.977198] udevd[128]: starting version 3.2.9
[ 5.032129] udevd[129]: starting eudev-3.2.9
[ 6.661121] EXT4-fs (vda): re-mounted. Opts: (null)
[ 6.661534] ext4 filesystem being remounted at /
supports timestamps until 2038 (0x7fffffff)
root@qemuarm:~# fahr 20
68
Recette d’image
L’utilisation du fichier local.conf pour l’ajout de recette n’est cependant
pas la méthode la plus usuelle et lorsque la configuration est prête, il est
conseillé de créer une recette d’image dérivée des exemples fournis par
37
Yocto (ou par le BSP). Dans le cas de la Raspberry Pi, voici quelques
exemples dans le répertoire meta-raspberrypi/recipes-core/images .
$ ls -1
rpi-basic-image.bb
rpi-hwup-image.bb
rpi-test-image.bb
On peut donc créer dans notre layer une recette d’image spécifique qui
intègre notre paquet ajouté ce qui correspond au fichier de recette
meta-example-lb/recipes-core/images/images/lb-test-image.bb
dont le contenu est le suivant :
# Added packages
IMAGE_INSTALL += "fahr"
# Added features
IMAGE_FEATURES += "package-management"
$ bitbake lb-test-image
38
qemuarm login: root
root@qemuarm:~# fahr 20
68
psplash
├── files
│ ├── psplash-init
│ ├── psplash-poky-img.h
│ ├── psplash-start.service
│ └── psplash-systemd.service
└── psplash_git.bb
39
ce fichier mais les sources de Yocto étant gérées sous Git, nous rappelons
qu’il est très déconseillé de modifier la recette initiale. On pourrait également
dupliquer la recette dans le layer meta-example-lb puis modifier les
composants mais cette méthode est limitée car les modifications devront être
reportées à chaque mise à jour de la recette par la communauté Yocto.
Principe du .bbappend
Le principe est de créer - dans un autre layer - une recette étendue (suffixe
.bbappend) permettant de modifier les éléments de la recette tout en
conservant le fichier .bb initial.
Si on reprend l’exemple de la recette précédente, l’arborescence de notre
nouvelle recette étendue est la suivante :
meta-poky/recipes-core/psplash/
├── files
│ └── psplash-poky-img.h
└── psplash_git.bbappend
FILESEXTRAPATHS_prepend_poky := "${THISDIR}/files:"
$ bitbake-layers show-appends
40
Cette liste contient les .bbappend correspondant à des .bb pour la liste des
layers chargés dans l’environnement de compilation. Suivant la valeur de la
variable DISTRO, les images utilisent des paramètres définis par la
distribution (voir meta/conf/distro/poky.conf). En plus de fournir des
images spécifiques (voir précédemment), certains BSP fournissent des
distributions spécifiques (cas des BSP pour les modules i.MX).
$ ls sources/meta-boundary/recipes-boundary/images/
boundary-image-multimedia-full.bb
$ ls sources/meta-freescale-distro/conf/distro/
fslc-framebuffer.conf fslc-xwayland.conf fsl-x11.conf
fslc-wayland.conf fsl-framebuffer.conf
fsl-xwayland.conf
fslc-x11.conf fsl-wayland.conf include
recipes-core/mypack-auto/
├── files
│ └── hello.patch
└── mypack-auto_1.0.bbappend
$ tree recipes-kernel/linux-raspberrypi
recipes-kernel/linux-raspberrypi/
└── linux-raspberrypi_%.bbappend
$ cat
recipes-kernel/linux-raspberrypi/linux-raspberrypi_%.bbappe
41
nd
KERNEL_MODULE_AUTOLOAD += "i2c-dev"
Au début de ce livre, nous avons évoqué les étapes (et donc les fonctions)
utilisées par BitBake. Grâce à l’extension de recette, on peut facilement
ajouter une étape exécutée avant ou après une étape standard. Dans
l’exemple suivant, on active le bus I2C d’une Raspberry Pi en modifiant le
fichier config.txt après son déploiement sur tmp/deploy/image.
$ cat recipes-bsp/bootfiles/rpi-config_git.bbappend
do_deploy_append() {
# Enable i2c by default
echo "dtparam=i2c_arm=on" >>
${DEPLOYDIR}/bootfiles/config.txt
}
Utilisation de Devtool
La commande devtool est fournie dans l’environnement Yocto et permet
d’effectuer différentes opérations sur les recettes :
● Créer une recette à partir des sources du composant (add)
● Modifier une recette existante sur la base d’une modification des
sources originaux (modify)
● Mettre à jour d’une recette suite à la mise à jour des sources
« upstream » (update)
La deuxième option est souvent utilisée et nous allons la tester dans ce livre
en reprenant l’exemple de la recette fahr pour modifier simplement le format
d’affichage. Grâce à Devtool, nous allons créer un .bbappend pour la recette
modifiée par un patch.
En premier lieu, nous créons un nouveau layer pour héberger la recette
étendue.
42
$ bitbake-layers add-layer ../meta-example-lb-ext
$ cd workspace/sources/fahr
$ vi fahr.c
$ git commit -a -m "updated format"
meta-example-lb-ext/recipes-example/fahr
├── fahr
│ └── 0001-Updated-format.patch
└── fahr_%.bbappend
root@qemuarm:~# fahr 20
20 °C -> 68 °F
43
Production du SDK
Un compilateur croisé est produit lors de la première production de l’image
mais cette version n'est pas utilisable à l'extérieur de Yocto (sauf en utilisant
bitbake -c devshell, ce qui n’a que peu d’intérêt). Il est possible de
créer un compilateur croisé que l'on pourra installer sur une machine
compatible même si elle ne dispose pas de l'environnement Yocto. Pour cela
on peut utiliser la commande bitbake meta-toolchain qui produit une
archive du SDK dans tmp/deploy/sdk (sous la forme d'un script à
exécuter). Une option plus avancée permet de créer un SDK contenant non
seulement le compilateur mais également les bibliothèques spéciales
installées sur la cible par des recettes ajoutées. Pour cela on utilise la
commande :
$ sudo
tmp/deploy/sdk/poky-glibc-x86_64-meta-toolchain-armv7vet2hf
-neonqemuarm-toolchain-3.1.6.sh
Utilisation du compilateur
Pour utiliser la chaîne de compilation, on charge les variables
d’environnement nécessaire en utilisant de nouveau la commande source et
un script fourni par Yocto.
$ source
/opt/poky/3.1.6/environment-setup-armv7vet2hf-neon-poky-lin
ux-gnueabi
44
La variable CC (habituellement vide) contient désormais le nom de la
commande du compilateur croisée ainsi que les options indispensables à son
utilisation.
$ echo $CC
arm-poky-linux-gnueabi-gcc -march=armv7ve -mthumb
-mfpu=neon -mfloat-abi=hard
--sysroot=/opt/poky/3.1.6/sysroots/armv7vet2hf-neon-poky-li
nux-gnueabi
Bien entendu, ce compilateur peut être utilisé avec des outils classiques
comme Autotools ou CMake. On peut par exemple compiler les sources de
l’exemple précédent (le programme fahr) avec ce compilateur. L’outil CMake
prend en compte le contenu de la variable CC pour utiliser le compilateur
croisé adéquat et produire le fichier Makefile.
$ cd fahr-2.0
$ mkdir build && cd build
$ cmake ..
$ make
Scanning dependencies of target fahr
[ 50%] Building C object CMakeFiles/fahr.dir/fahr.o
[100%] Linking C executable fahr
[100%] Built target fahr
$ cd mypack-auto
45
$ autoreconf -f -i -v
$ mkdir build && cd build
$ ../configure --host=arm-poky-linux-gnueabi
$ make
Intégration continue
L’intégration continue (IC ou CI) est un sujet phare dans l’industrie du logiciel.
Ce point est particulièrement crucial pour les systèmes embarqués qui
doivent avoir une fiabilité exemplaire soit parce qu’ils sont largement diffusés
soit parce qu’ils assurent des tâches sensibles (et souvent les deux !). L’IC
permet de vérifier que la mise à jour d’un composant ne provoque pas de
régression sur le fonctionnement du système. L’outil Yocto permet de
dérouler des tests à deux niveaux :
10 50
20 68
30 86
46
Le script (qui doit être nommé run-ptest), lit le tableau et compare la valeur
de la deuxième colonne avec le résultat produit par l’exécutable fahr en
utilisant la valeur de la première colonne en entrée du programme. Ce script
est écrit en shell, mais on pourrait très bien utiliser un autre langage.
#!/bin/sh
R=0
while read line
do
set $line
if [ "$(fahr $1)" != "$2" ]; then
R=1
break
fi
done < test.dat
if [ $R -eq 0 ]; then
echo PASS
else
echo FAILED
fi
exit $R
fahr
├── fahr_2.0.bb
└── files
├── run-ptest
└── test.dat
Le contenu du fichier de recette est également mis à jour comme suit. Nous
faisons apparaître les modifications en gras.
47
DESCRIPTION = "Celsius to Fahrenheit utility (CMake based)"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM =
"file://COPYING;md5=8ca43cbc842c2336e835926c2166c28b"
PR = "r0"
SRC_URI = "http://pficheux.free.fr/pub/tmp/fahr-2.0.tar.gz"
SRC_URI += "file://run-ptest file://test.dat"
do_install_ptest () {
cp ${WORKDIR}/test.dat ${D}${PTEST_PATH}
}
SRC_URI[md5sum] = "8cd41891470ea0e909181d3a1ec6d47e"
$ runqemu nographic
...
Poky (Yocto Project Reference Distro) 3.1.6 qemuarm ttyAMA0
48
qemuarm login: root
root@qemuarm:~# ptest-runner -l
Available ptests:
acl /usr/lib/acl/ptest/run-ptest
attr /usr/lib/attr/ptest/run-ptest
busybox /usr/lib/busybox/ptest/run-ptest
bzip2 /usr/lib/bzip2/ptest/run-ptest
fahr /usr/lib/fahr/ptest/run-ptest
libxml2 /usr/lib/libxml2/ptest/run-ptest
lzo /usr/lib/lzo/ptest/run-ptest
opkg /usr/lib/opkg/ptest/run-ptest
util-linux /usr/lib/util-linux/ptest/run-ptest
zlib /usr/lib/zlib/ptest/run-ptest
$ ls meta/lib/oeqa/runtime/cases/
apt.py gstreamer.py pam.py scp.py
49
boot.py kernelmodule.py parselogs.py
skeletoninit.py
buildcpio.py ksample.py perl.py ssh.py
buildgalculator.py ldd.py ping.py
stap.py
buildlzip.py logrotate.py ptest.py
storage.py
connman.py ltp_compliance.py __pycache__
systemd.py
date.py ltp.py python.py
weston.py
df.py ltp_stress.py _qemutiny.py
x32lib.py
dnf.py multilib.py rpm.py
xorg.py
gcc.py oe_syslog.py runlevel.py
gi.py opkg.py scons.py
INHERIT += "testimage"
TEST_SUITES = "ping"
Dans le cas de QEMU, l’image est exécutée puis les tests sont déroulés.
Suite à celà, l’exécution de l’image est interrompue avec affichage du
résultat.
50
NOTE: Tasks Summary: Attempted 601 tasks of which 599
didn't need to be rerun and all succeeded.
Fonctionnement de Buildroot
51
liste de fichiers defconfig, on peut aisément modifier les paramètres avec
l’IHM.
Configuration de Buildroot
$ cd <BR-src-dir>
$ make raspberrypi3_defconfig # chargement de la
configuration pour Pi 3
$ make menuconfig # modification de la
configuration (optionnel)
...
$ make # construction de l’image
52
La principale limitation de Buildroot est son approche « statique » car il n’est
pas basé sur la notion de layer externe. L’utilisation de la variable
BR2_EXTERNAL [13] permet certes d'utiliser un répertoire externe pour ajouter
des composants (répertoire package) des patch ou des fichiers de
configuration mais cette approche reste moins souple que celle de Yocto.
Rappelons également qu’une image Buildroot ne peut disposer d’un
gestionnaire de paquets comme avec Yocto. Il est vrai que la plupart des
images utilisées en production n’utilisent pas de gestionnaire de paquets
mais la disponibilité de cette option dans un environnement de
développement peut être un gros avantage.
53
Conclusion
Après avoir introduit les concepts de base liés aux systèmes basés sur Linux
embarqué, ce livre nous a permis d'évoquer le principal outil utilisable pour la
production d'une distribution Linux réduite et maîtrisée.
Buildroot peut convenir dans le cas d'un système simple pour lequel la
gestion de paquets n'est pas nécessaire. Cependant il a tout de même
quelques limitations quant à l'intégration de composants externes si on le
compare à Yocto, ce dernier étant beaucoup plus modulaire et dynamique.
Yocto nécessite cependant un plus grand investissement pour sa prise en
main (compter au minimum un mois pour un ingénieur expérimenté dans le
domaine Linux industriel). Cependant son approche très modulaire et sa large
utilisation du principe d'héritage en fait un outil très puissant pour la
maintenance d'une offre logicielle variée (plusieurs cartes et plusieurs
projets). Autre point et non des moindres, Yocto est de nos jours utilisé par la
plupart des fournisseurs de matériel et une connaissance de base de cet outil
est nécessaire pour l'exploitation des BSP disponibles. Enfin, Yocto est à la
base de plusieurs outils de développement commerciaux (comme ceux de
Wind River, SIEMENS, etc.) ce qui permettra de migrer sans trop d'effort les
travaux réalisés vers ces environnements si cela est nécessaire.
54
Bibliographie
[1] Apollo Guidance Computer
https://en.wikipedia.org/wiki/Apollo_Guidance_Computer
[2] Calculateur D17-B https://en.wikipedia.org/wiki/D-17B
[3] RTOS/360
https://www.computer.org/csdl/proceedings/afips/1969/5073/00/50730015.pdf
[4] Simulateur Javascript de l'AGC
http://svtsim.com/moonjs/agc.html
[5] Système MULTICS https://en.wikipedia.org/wiki/Multics
[6] SPS7 et SM-90
http://www.feb-patrimoine.com/projet/unix/sps7.htm
[7] Utiliser ELBE https://www.youtube.com/watch?v=BwHzyCGB7As
[8] Utiliser DEBOS https://www.youtube.com/watch?v=57Lmv1hG9T0
[9] BSP Yocto pour Raspberry Pi
http://git.yoctoproject.org/cgit/cgit.cgi/meta-raspberrypi
[10] BSP Yocto pour les modules Toradex
https://developer.toradex.com/knowledge-base/board-support-package/opene
mbedded-core
[11] Livre blanc « Mise à jour des systèmes embarqués » (Smile)
https://www.smile.eu/fr/livres-blancslivres-blancs/mise-jour-systemes-embarqu
es
[12] Utilisation de la classe « testimage »
https://www.yoctoproject.org/docs/latest/mega-manual/mega-manual.html#per
forming-automated-runtime-testing
[13] Project specific customization (Buildroot)
https://buildroot.org/downloads/manual/manual.html#customize
55
56