Les variables principales de Bitbake – 2 – Les variables contextuelles

Publié par cpb
Oct 01 2024

Nous avons vu dans l’article précédent qu’il existe de nombreuses variables pour configurer le comportement de Bitbake lors d’un build de Yocto Project. Nous avons examiné précédemment les variables globales, qui sont valables durant tout le build.

Nous allons étudier à présent les principales variables contextuelles (on parle aussi de variables « scopées ») qui ne sont valides que dans certains contextes.

Les contextes qui nous intéresseront ici sont ceux des recettes (.bb) et des amendements de recettes (.bbappend).

Petit conseil : lorsque vous soupçonnez une variable contextuelle de n’être pas correctement remplie, employez bitbake -e <recipe-name> | grep ^<variable> pour voir son contenu.

Voici un exemple :

$ bitbake  -e  vim | grep  ^SRC_URI
SRC_URI="git://github.com/vim/vim.git;branch=master;protocol=https            file://disable_acl_header_check.patch            file://vim-add-knob-whether-elf.h-are-checked.patch            file://0001-src-Makefile-improve-reproducibility.patch            file://no-path-adjust.patch            "

Le contenu de la variable n’est pas très bien formaté, mais il est lisible. Cela correspond bien à ce qui était renseigné dans la recette :

$ cat ../../layers/poky/meta/recipes-support/vim/vim.inc 
 [...]
SRC_URI = "git://github.com/vim/vim.git;branch=master;protocol=https \
           file://disable_acl_header_check.patch \
           file://vim-add-knob-whether-elf.h-are-checked.patch \
           file://0001-src-Makefile-improve-reproducibility.patch \
           file://no-path-adjust.patch \
           "

L’option -e de bitbake lui demande de ne pas faire le build attendu, mais d’afficher sur sa sortie standard le contenu de son environnement (ses variables et ses fonctions). En précédant le nom de la variable par ^ nous nous assurons qu’elle est alignée en début de ligne. C’est donc une ligne d’initialisation de la variable, et non pas une ligne où elle est intégrée dans une autre variable.

Comme dans l’article précédent, je suis obligé de faire une sélection dans la liste imposante de variables configurant le comportement de bitbake. J’ai choisi de retenir les variables que je me souviens avoir configurées (ou dont j’ai examiné le contenu) durant les derniers mois.

L’objectif n’est pas de faire une description complète de l’utilisation d’une variable donnée, pour cela la documentation de Yocto Project est la référence, mais plutôt de fournie une liste inverse, où l’on part du résultat attendu pour retrouver le nom d’une variable précise.

Pour cela j’ai regroupé les variables par problématique et obtenu la liste suivante :

Sauf mention particulière, les variables contextuelles des recettes sont facultatives. Il en existe très peu (3) qui sont obligatoires.

1 – Informations sur la recette

Le début d’une recette est généralement consacré à des variables d’information sur la recette. Cela permet de savoir qui a écrit la recette elle-même et d’avoir une idée de son contenu.

Traçabilité

  • SUMMARY contient une brève description (une ligne de 72 caractères au maximum) du contenu de la recette. C’est ce qu’on affiche lorsqu’on présente une liste de recettes comme sur le site OpenEmbedded Layer Index.
  • DESCRIPTION permet une présentation plus détaillée du contenu. On peut présenter ce champ sur une page dédiée à une recette par exemple.
  • RECIPE_MAINTAINER, contient le nom et l’adresse mail de l’auteur de la recette. Bien qu’assez rarement présent, ce champ est utile lorsqu’on intègre une recette indépendante (trouvée sur GitHub par exemple) dans un layer personnel. Cela permet de faire part à l’auteur original des corrections ultérieures apportées à sa recette.
  • HOMEPAGE est un champ purement informatif qui permet de retrouver facilement les informations prises comme références lors de la rédaction de la recette. Ceci est surtout utile dans le cas d’un projet peu connu et dont l’origine exacte n’est pas évidente.

Licence

On sait l’importance que Yocto Project apporte à la connaissance des termes des licences de tous les composants embarqués dans une image. Ceci est extrêmement important pour s’assurer de la bonne cohabitation de tous les packages, d’autant plus dans des environnements industriels où les systèmes embarqués doivent intégrer des logiciels propriétaires.

  • LICENSE indique la licence (ou la liste de licences) sous laquelle le code géré par la recette est distribué. Cette variable est obligatoire dans toutes les recettes. Lorsque le projet contient des fichiers sources fournis sous différentes licences, on associe leurs noms avec un caractère &. Lorsqu’il est possible de choisir entre les termes de différentes licences, on utilise le caractère |.
  • LIC_FILES_CHKSUM est la deuxième variable obligatoire dans toutes les recettes (la troisième sera SRC_URI) sauf dans le cas où LICENSE contient CLOSED. Il s’agit de la liste des checksums des fichiers contenant les termes des licences indiquées dans LICENSE. De cette façon l’auteur de la recette précise quelle version des fichiers il a consulté pour déterminer le type de licence. Lorsqu’il n’y a pas de fichier de licence livré avec les sources, on peut utiliser ceux fournis dans le répertoire ${COMMON_LICENSE_DIR} de Poky.
  • NO_GENERIC_LICENSE est utilisé pour préciser que la recette utilise une licence personnelle non générique (et différente de CLOSED). On peut préciser que le texte de la licence se trouve dans un fichier téléchargé dans l’étape do_fetch() avec la notation
    NO_GENERIC_LICENSE[<license-name>] = "<license-file>"
  • LICENSE_FLAGS peut contenir un nom de licence personnalisé qu’il faudra obligatoirement inscrire dans la variable globale LICENSE_FLAGS_ACCEPTED (dans le fichier local.conf) pour pouvoir compiler la recette.

2 – Obtention des fichiers sources

Emplacement des sources

  • SRC_URI est une des trois variables obligatoires pour toutes les recettes (avec LICENSE et LIC_FILES_CHKSUM). Il s’agit de la liste des fichiers que bitbake doit se procurer lors de l’étape do_fetch() pour produire le résultat de la recette.
  • SRCREV contient le numéro de version à extraire (pour les protocoles git://, svn://, hg:// et bzr://). Avec git://, il peut s’agir d’un hash SHA ou d’un tag. La spécification
    SRCREV=${AUTOREV}
    charge toujours la dernière version du projet source.
  • FILESEXTRAPATHS contient les emplacements où chercher les fichiers préfixés par file:// en supplément des chemins usuels de bitbake. Cette variable est surtout utilisée dans les fichiers d’amendement de recette .bbappend ainsi :
    FILESEXTRAPATHS:prepend := “${THISDIR}/${PN}:”
  • EXTERNALSRC est une variable qui prend sa signification lorsque la recette hérite de la classe "externalsrc". On peut y indiquer le répertoire des sources (pendant une phase de développement par exemple) de la recette. Dans ce cas les étapes do_fetch(), do_unpack() et do_patch() sont ignorées, le chemin pointé par EXTERNALSRC est inscrit dans la variable S.

Versions et mises à jour

  • UPSTREAM_CHECK_URI peut contenir l’URL des sources, qui sera consultée lorsqu’on appelle la commande
    devtool latest-version <recipe-name>
    pour vérifier si une nouvelle version est disponible.
  • UPSTREAM_CHECK_COMMITS est une variable booléenne. Quand elle vaut « 1 » le contenu de UPSTREAM_CHECK_URI est considéré comme un dépôt Git et la commande
    devtool latest-version <recipe-name>
    vérifie et affiche le numéro du dernier commit.

Vérification des vulnérabilités

  • CVE_PRODUCT contient le nom à prendre en considération pour le package lorsque bitbake vérifie la présence de vulnérabilités connues (quand la variable globale INHERIT contient le nom de la classe « cve-check« ).
  • CVE_VERSION contient le numéro de version à prendre en compte pendant la vérification de la base de données des vulnérabilités.
  • CVE_STATUS contient une table CVE_STATUS[<cve-id>] = "reason" donnant la justification pour laquelle une vulnérabilité connue pour ce package doit être ignorée.

3 – Compilation

  • EXTRA_AUTORECONF et EXTRA_OECONF sont utilisées dans les recettes héritant de la classe autotools pour passer des arguments à autoreconf et au script configure.
  • EXTRA_OEMAKE et EXTRA_OECMAKE contiennent des options pour les commandes make et cmake.
  • TARGET_CFLAGS, BUILD_CFLAGS et BUILDSDK_CFLAGS contiennent les paramètres à placer dans la variable CFLAGS pendant les compilations respectives pour la cible, le système de build et le SDK. Le même rôle est jouée par les variables TARGET_CXXFLAGS etc. pour CXXFLAGS, et TARGET_LDFLAGS etc. pour LDFLAGS.
  • S contient l’emplacement des sources à compiler. bitbake essaye de « deviner » cet emplacement à partir de l’étape do_unpack() mais il est souvent nécessaire de lui ajouter des précisions quand l’arborescence extraite n’est pas triviale (par exemple S="${WORKDIR}/sources").
  • B et D représentent respectivement le répertoire de build et celui d’installation de l’arborescence destinée à la cible. On peut être amené à modifier B pour éviter les conflits avec S, en revanche on ne modifie pas D.
  • EXTERNALSRC_BUILD doit être renseignée avec l’emplacement où stocker les résultats de compilation lorsque la recette hérite de la classe externalsrc.
  • PACKAGES contient la liste des packages binaires à créer pendant la compilation. Par défaut , PACKAGES vaut "${PN}-src ${PN}-dbg ${PN}-staticdev ${PN}-dev ${PN}-doc ${PN}-locale ${PACKAGE_BEFORE_PN} ${PN}" mais on peut retirer ${PN}-dbg par exemple si on n’envisage pas d’utiliser les symboles de debug.
  • BBCLASSEXTEND est une variable qui contient la liste des extensions de packages à compiler. On peut être amenés à insérer dans une recette BBCLASSEXTEND += "native" ou "nativesdk" pour indiquer qu’elle doit être également compilée pour la machine hôte ou intégrée dans le SDK.

4 – Gestion des dépendances

Dépendances et conflits entre recettes

  • DEPENDS contient la liste des dépendances nécessaires pour compiler la recette, RDEPENDS (R pour runtime) liste les dépendances nécessaires pour installer la recette sur la cible. Les dépendances sont classiquement des noms de packages.
  • PROVIDES et RPROVIDES indiquent les fonctionnalités offertes par une recette pendant la phase de compilation et l’installation sur la cible. Ces fonctionnalités sont utilisables dans les variables DEPENDS et RDEPENDS d’autres recettes.
  • RRECOMMENDS liste les packages supplémentaires que l’on suggère d’installer sur la cible en complément de la recette courante. La variable globale BAD_RECOMMENDATIONS permet de refuser l’installation automatique de certains packages conseillés.
  • RCONFLICTS contient une liste de packages en conflit avec la recette. Si l’un de ces packages est présent sur la cible, le produit de la recette ne pourra pas y être installé.
  • RREPLACES indique une liste de packages obsolètes remplacés par la recette lors d’une évolution du système.

Fonctionnalités de distro

  • REQUIRED_DISTRO_FEATURES liste les fonctionnalités qui doivent toutes être présentes dans la variable globale DISTRO_FEATURES pour que la recette puisse être compilée. ANY_OF_DISTRO_FEATURES liste les fonctionnalités dont au moins une doit être présente dans DISTRO_FEATURES.
  • CONFLICT_DISTRO_FEATURES liste les fonctionnalités de distro qui sont incompatibles avec la compilation de la recette. Cette variable reflète souvent les antagonismes XWindow/Wayland ou sysVinit/systemd par exemple.

5 – Installation sur la cible

Fichiers installés

  • FILES est une variable qui contient la liste des fichiers et répertoires installés par une recette. Cette variable doit toujours être utilisée avec l’override FILES:${PN}.
  • CONFFILES est également une variable toujours utilisée avec l’override CONFFILES:${PN}. Elle contient la liste des fichiers utilisés pour la configuration dynamique du système cible. Ces fichiers ne seront pas écrasés dans le cas d’une mise à jour du package sur la cible.
  • ALTERNATIVE contient la liste des commandes de la recette qui sont susceptibles de se trouver également implémentées par une autre recette. L’exemple typique est celui de Busybox qui implémente de très nombreuses commandes que l’on trouve également dans leurs propres packages.
  • ALTERNATIVE_LINK_NAME est un tableau associatif qui contient le chemin du lien symbolique que bitbake doit créer vers une commande alternative, le format est
    ALTERNATIVE_LINK_NAME[<command>] = "/<path>/<command>"
  • ALTERNATIVE_PRIORITY est également un tableau associatif indexé par le nom de commande, qui indique sa priorité par rapport aux implémentations dans d’autres recettes. L’implémentation de priorité la plus élevée est utilisée comme cible du lien. Le format est
    ALTERNATIVE_PRIORITY[<command>] = "<value>"

Lancement au boot

  • INITSCRIPT_NAME contient le nom du script à exécuter au démarrage lorsque le système de démarrage est du type sysVinit. La recette doit hériter de la classe update-rc.d. Le script devra être copié pendant l’étape do_install() dans ${D}${sysconfdir}/init.d
  • INITSCRIPT_PARAMS contient dans ce cas les paramètres pour update-rc.d, c’est-à-dire des séquences commençant par start ou stop suivi du numéro d’ordre de démarrage du service, des runlevels concernés et d’un point « .« .
  • SYSTEMD_SERVICE est une variable que l’on utilise avec l’override SYSTEMD_SERVICE:${PN} pour indiquer le nom du fichier de service pour systemd (qui doit également être copié pendant l’étape do_install() dans ${D}/${systemd_system_unitdir}). Il faut que la recette hérite de la classe « systemd« .
  • SYSTEMD_AUTO_ENABLE peut contenir la chaîne de caractères « enable » pour que le service indiqué ci-dessus démarre automatiquement au boot.

6 – Spécificités des recettes kernel

Une recette pour le noyau Linux doit hériter de la classe kernel. Certaines variables présentées ci-dessous sont en réalité des variables globales, mais on les définit toujours dans la recette du noyau.

  • COMPATIBLE_HOST est une variable que l’on peut rencontrer dans n’importe quelle recette, mais c’est surtout dans les recettes du kernel et du bootloader qu’elle a du sens. Il s’agit d’une expression rationnelle qui est comparée avec le contenu de la variable globale HOST_SYS (remplie automatiquement avec ${HOST_ARCH}-${HOST_VENDOR}-${HOST_OS}) pour savoir si la recette peut être compilée.
  • COMPATIBLE_MACHINE est une expression rationnelle qui est comparée avec les éléments de la variable globale MACHINEOVERRIDES pour savoir si la recette peut être compilée. On utilise une notation comme :
    COMPATIBLE_MACHINE = "^(arm|aarch64)$"
  • KMACHINE contient le nom de la machine pour le noyau, qui n’est pas nécessairement le même nom que celui pour le reste du build (dans la variable globale MACHINE).
  • KBRANCH est une variable globale configurée dans la recette kernel, qui contient le nom de la branche à utiliser pour les sources du kernel.
  • LINUX_VERSION doit contenir le numéro officiel (par exemple 6.6.52) de version du noyau utilisé.
  • LINUX_VERSION_EXTENSION est une chaîne de caractères ajouté au numéro de version du noyau. On s’en sert parfois pour identifier la provenance du noyau sur lequel on a démarré, grâce à la commande « uname -r« .
  • KBUILD_DEFCONFIG contient le nom de la configuration interne au kernel à utiliser. Le mode d’utilisation est :
    KBUILD_DEFCONFIG:<machine> = "<kmachine>_defconfig"
  • KERNEL_DEVICETREE est une variable utilisée lorsque la recette hérite de la classe « kernel-devicetree« , elle contient le nom du fichier .dtb à produire.
  • DT_FILES_PATH contient l’emplacement des fichiers sources pour le device tree (.dts et .dtsi) lorsqu’ils sont fournis en dehors des sources du noyau. La recette doit hériter de la classe « kernel-devicetree« .
  • KERNEL_PACKAGE_NAME contient le nom de base du package du noyau (en général « kernel« ) pour nommer ensuite les packages des modules, l’image binaire, etc.

Conclusion

Nous avons étudié dans cette petite série de trois articles plusieurs éléments de configuration de Yocto Project :

  • Tout d’abord la liste des fichiers parcourus lors du build, leur ordre et la logique sous-jacente. En nous concentrant sur les fichiers de configuration dans lesquels on intervient habituellement.
  • Puis une liste de variables globales, disponibles pendant tout le build, en essayant de les classer logiquement en fonction de leur utilisation.
  • Enfin des variables contextuelles utilisées dans les recettes et dont la portée est limitée à la recette où elles sont définies.

J’espère que ces éléments sauront vous être utiles pour éclairer certains aspects un peu obscurs du build de Yocto Project.

La prochaine série d’articles, qui débutera dans deux semaines, sera consacré à un tout autre sujet : le système d’exploitation pour microcontrôleurs Zephyr OS !

Pour en savoir plus sur Yocto et Bitbake et mettre en pratique les éléments aperçus dans cet article, n’hésitez pas à participer à une session de formation « Linux embarqué avec Yocto Project » ou « Yocto Project avancé » que j’anime chez Logilin.

URL de trackback pour cette page