Les fichiers de configuration de Bitbake

Publié par cpb
Sep 03 2024

Lorsqu’on réalise un build pour un système Linux embarqué avec Yocto Project, de nombreux fichiers sont parcourus par l’outil Bitbake. Il n’est pas toujours simple de savoir dans quel ordre ces fichiers de configuration sont examinés, mais c’est pourtant une clé pour la bonne compréhension des opérations réalisées.

Nous allons nous intéresser ici aux fichiers de configuration et de données (distro, machine, image, recettes, etc.) pas aux fichiers python internes de Bitbake, ni aux fichiers sources, objets ou exécutables obtenus lors de la compilation des packages.

Bien sûr nous regarderons certains fichiers directement livrés avec Yocto, mais ce qui m’intéresse avant tout, c’est la connaissance des fichiers sur lesquels nous avons la possibilité d’agir, ceux que nous pouvons personnaliser avant de lancer le build.

Environnement de travail

Nous allons nous placer dans une situation assez simple mais réaliste pour un petit projet :

  • préparation d’une image pour Raspberry Pi 4 réalisée en utilisant la branche Scarthgap de Poky,
  • utilisation du layer meta-raspberrypi,
  • utilisation du layer meta-oe se trouvant dans le repository meta-openembedded.

Pour être certain de voir tous les accès aux fichiers demandés par bitbake, je l’ai lancé en le préfixant par « strace -f -o bitbake-trace.txt » afin d’obtenir dans le fichier bitbake-trace.txt la liste de tous les appels-système invoqués lors du build.

Je me suis retrouvé avec un fichier de traces de 270Go ! J’en ai extrait les lignes qui contiennent un appel open() – ou plus précisément openat() – qui n’échoue pas. Puis j’ai filtré le résultat pour ne conserver que les extensions de fichiers qui m’intéressent (.bb, .conf, .bbappend, .bbclass , etc.).

J’ai obtenu au final un fichier de 8.3 Mo, comprenant 95110 lignes. Comme il s’agit des opérations séquentielles lors du build, de nombreux accès aux fichiers sont redondants (par exemple les classes sont héritées par de nombreuses recettes différentes). Si on élimine les redondances, il n’y a « que » 8158 fichiers parcourus.

Partant de cette base de travail et en consultant le véritable contenu des fichiers, on peut comprendre assez bien l’enchaînement des opérations pour Bitbake.

Fichiers de configuration

Le comportement général de Bitbake est le suivant :

  1. lire les informations de configuration globale,
  2. parcourir les layers par ordre de priorité croissante et mémoriser le contenu des recettes (une recette .bbappend dans un layer de priorité élevée peut amender le contenu de la recette .bb de même nom située dans un layer de priorité plus faible),
  3. réaliser les actions nécessaires pour obtenir la cible réclamée au lancement de la commande (image, recette, etc.).

Ici nous ne nous intéressons qu’aux deux premiers points. Pour être exact c’est même le premier point qui nous concerne le plus.

Liste des layers concernés

Le premier fichier lu par bitbake est conf/bblayers.conf. Il renseigne principalement la variable BBLAYERS qui contient la liste des layers à prendre en considération. Voici un extrait de ce fichier :

BBLAYERS ?= " \
  /home/Builds/Lab/layers/poky/meta \
  /home/Builds/Lab/layers/poky/meta-poky \
  /home/Builds/Lab/layers/poky/meta-yocto-bsp \
  /home/Builds/Lab/layers/meta-raspberrypi \
  /home/Builds/Lab/layers/meta-openembedded/meta-oe \
  "

Le fichier conf/bblayers.conf peut être manipulé manuellement ou par l’intermédiaire de la commande bitbake-layers.

Configurations des layers

Bitbake va ensuite lire les cinq fichiers conf/layer.conf se trouvant à l’intérieur des cinq répertoires mentionnés ci-dessus. Cela va lui permettre d’obtenir des informations sur les layers, entre autres :

  • Vérifier la compatibilité des layers avec la branche de Poky (par exemple : LAYERSERIES_COMPAT_openembedded-layer = "scarthgap").
  • Obtenir les priorités respectives des layers (BBFILE_PRIORITY_openembedded-layer = "5"), c’est-à-dire l’ordre de parcours à venir.
  • Mémoriser les emplacements des recettes contenues dans les layers (BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend)

Lorsque nous créons notre propre layer (par exemple avec la commande « bitbake-layers create-layer <layer-path> » ) un fichier layer.conf est créé avec des valeurs par défaut. Il est conseillé de le consulter et d’ajuster éventuellement la priorité et la compatibilité avec Poky.

Configuration de bitbake

Le fichier lu ensuite par Bitbake se trouve dans le layer poky/meta, juste à côté de layer.conf. Il s’agit de conf/bitbake.conf et il a une très grande importance pour le reste du build.

Dans ce layer se trouvent tout d’abord l’initialisation d’un grand nombre de variables :

  • les noms symboliques des chemins qu’on utilise dans les recettes (comme ${bindir} ou ${sysconfdir}),
  • les informations sur la machine hôte, sur la cible, sur la machine prévue pour héberger le SDK, etc.
  • les valeurs par défaut pour les variables renseignées ou utilisées dans les recettes (SUMMARY, LICENSE, SRC_URI, PN, PV, DEPENDS, FILES, WORKDIR, D, S, B…),
  • les valeurs par défaut pour les paramètres de build (TCLIBC, MAKE, CC, DISTRO, OVERRIDES, DL_DIR, SSTATE_DIR, …)
  • l’initialisation de variables utilisées dans de nombreuses recettes (IMAGE_FEATURES, DISTRO_FEATURES, MACHINE_FEATURES, etc.)
  • etc.

Le second aspect extrêmement important de ce fichier, c’est qu’il va organiser l’inclusion de tous les autres fichiers de configuration. Voici la portion concernée :

require conf/abi_version.conf
include conf/site.conf
include conf/auto.conf
include conf/local.conf
require conf/multiconfig/${BB_CURRENT_MC}.conf
include conf/machine/${MACHINE}.conf
include conf/machine-sdk/${SDKMACHINE}.conf
include conf/distro/${DISTRO}.conf
include conf/distro/defaultsetup.conf
include conf/documentation.conf
include conf/licenses.conf
require conf/sanity.conf
require conf/cve-check-map.conf
include conf/bblock.conf

Rappelons que la directive require concerne une inclusion obligatoire (sous peine d’échec du build) alors que include concerne un fichier facultatif.

Les fichiers de cette liste ne sont pas tous aussi intéressants. Nous allons nous concentrer sur les cinq que j’ai surligné, car ce sont les principaux points de configuration où nous pouvons être amenés à intervenir.

Configuration spécifique pour le développeur

Le fichier conf/site.conf est facultatif. Aucune version n’en est fournie par Yocto. Il est toutefois tout à fait possible d’en ajouter un dans le sous répertoire conf/ de notre dossier de build (à côté de bblayers.conf et de local.conf que nous allons voir ensuite).

Le rôle de ce fichier est habituellement de configurer les paramètres liés à l’environnement de build local. Ceux qui ne doivent pas être partagés avec les autres développeurs, par exemple des répertoires downloads/ ou sstate-cache/ à des emplacements particuliers, ou une configuration d’utilisation du processeur BB_NUMBER_THREADS ou PARALLEL_MAKE.

Dans le projet Yocto Cooker, nous n’avons choisi de ne pas inclure (pour le moment du moins) site.conf dans le format des menus de configuration. Ceux-ci doivent en effet pouvoir être partagés entre les développeurs utilisant Yocto.

Configuration du build

Avant de parcourir les layers ainsi mémorisés, bitbake va lire le fichier conf/local.conf qui va lui donner plusieurs renseignements importants :

  • La variable MACHINE qui indique le nom du fichier de configuration de la cible. C’est généralement la première variable que l’on configure pour notre build.
  • La variable SDK_MACHINE sert lors de l’extraction de l’environnement de développement (pour produire du code en dehors de Yocto et l’intégrer directement sur la cible).
  • les variables DL_DIR, SSTATE_DIR ou TMP_DIR qui indiquent les chemins utilisés durant le build.
  • La variable PACKAGE_CLASSES qui définit le format des packages binaires utilisés en interne par bitbake durant le build.
  • La variable DISTRO contient le nom de la distribution.
  • etc.

Le fichier conf/local.conf est généralement le premier point de personnalisation pour Yocto Project. Il est important de sauvegarder son contenu et celui de conf/bblayers.conf pour assurer la reproductibilité du build. C’est pourquoi le menu de configuration de Yocto Cooker contient une section spécifique pour mémoriser et re-générer ce fichier.

Configuration de la machine cible

La variable MACHINE indique le nom de la machine cible. Bitbake va alors rechercher dans les différents layers un fichier conf/machine/${MACHINE}.conf. Dans le cas du build ci-dessus, il s’agissait de conf/machine/raspberrypi4.conf se trouvant dans le layer meta-raspberrypi.

Ce fichier va lui-même inclure d’autre fichiers du même layer (rpi-base.inc , rpi-default-settings.inc, rpi-default-providers.inc, etc.)

Ce fichier configure tout ce qui concerne l’aspect hardware du build. On y trouve par exemple :

  • TUNE_FEATURES qui décrit les spécificités du processeur à destination de la toolchain de compilation (armv7a, neon, thumb, etc.)
  • MACHINE_FEATURES qui contient une liste de fonctionnalités offertes par le matériel (wifi, bluetooth, keyboard, etc.) qui pourront être testées dans les recettes pour inclure ou paramétrer certains packages.
  • WKS_FILE et IMAGE_FSTYPES indiquant le partitionnement et les formats de sortie pour le root filesystem.
  • PREFERRED_PROVIDER_virtual/kernel et PREFERRED_VERSION_<kernel> : la recette à utiliser pour compiler le kernel et sa version.
  • KERNEL_DEVICETREE le nom du device tree à utiliser pour ce hardware.
  • PREFERRED_PROVIDER_virtual/bootloader et PREFERRED_VERSION_<bootloader> indiquant la recette pour le bootloader et sa version.
  • etc.

Configuration de la machine de développement

Un autre fichier, moins connu que le précédent est parcouru par Bitbake, afin de connaître les options de compilation à appliquer lorsque l’on veut préparer la toolchain de cross-compilation en dehors de Yocto. Il s’agit de l’environnement obtenu quand on exécute bitbake -c populate_sdk <image-name>.

Je n’ai jamais rencontré de situation où l’on utilise un autre fichier de configuration que poky/meta/conf/machine-sdk/x86_64.conf même si d’autres architectures sont proposées :

$ ls ../../layers/poky/meta/conf/machine-sdk/
aarch64.conf i586.conf i686.conf loongarch64.conf ppc64.conf ppc64le.conf riscv64.conf x86_64.conf

Configuration de la distribution

Enfin le dernier fichier de configuration qui nous intéresse est conf/distro/${DISTRO}.conf.

Rappelons que la variable DISTRO est renseignée dans conf/local.conf avec la valeur par défaut poky. Le fichier concerné est donc poky/meta-poky/conf/distro/poky.conf. Outre des paramètres comme le nom de la distribution et son numéro de version, le rôle principal de ce fichier sera l’initialisation de variables comme DISTRO_FEATURES, DISTRO_EXTRA_RDEPENDS ou DISTRO_OVERRIDES. Ces variables permettront de sélectionner certains packages dans les recettes ou d’activer des options spécifiques lors de la compilation des packages.

Depuis la version Scarthgap de Poky, nous sommes fortement incités à surcharger ce fichier, en créant notre propre distro et en plaçant le fichier de configuration dans le sous-répertoire conf/distro/ d’un layer personnel. Tant que nous utilisons la distribution poky par défaut, un message d’avertissement s’affiche lors de la connexion de l’utilisateur. Ce message se trouve dans le fichier suivant :

$ cat ../../layers/poky/meta-poky/recipes-core/base-files/files/poky/motd 

WARNING: Poky is a reference Yocto Project distribution that should be used for
testing and development purposes only. It is recommended that you create your
own distribution for production use.

Configuration personnalisée

Nous voici donc avec cinq emplacements que nous pouvons personnaliser pour la configuration du build. Bien sûr viendront ensuite les ajustements de la recette d’image et des recettes de packages.

J’ai tendance à préférer intégrer le maximum de configuration au niveau de la distribution (dans conf/distro/<distro-name>.conf) et de la description de la cible (dans conf/machine/<machine-name>.conf), car ces fichiers se trouvent dans un layer personnalisé ce qui simplifie leur versioning et leur partage avec d’autres développeurs. Les fichiers site.conf et local.conf se trouvant dans le répertoire de build, leur sauvegarde réclame un mécanisme spécifique – par exemple Yocto Cooker 🙂 .

Pour définir sa propre distribution, il suffit d’ajouter un fichier conf/distro/<distro-name>.conf dans un layer nous appartenant, et de rajouter la ligne DISTRO = "<distro-name>" dans local.conf. Pour créer le fichier, on peut s’inspirer de celui de Poky, en élaguant les fonctionnalités inutiles pour notre projet (dans un premier temps, il suffit même d’inclure conf/distro/poky.conf avant de surcharger les variables de description).

De même, la définition d’une machine revient à ajouter un fichier conf/machine/<machine-name>.conf dans notre layer et une ligne MACHINE="<machine-name>" dans local.conf. Souvent, on inclut directement la configuration de la machine d’origine en intervenant simplement sur le device tree.

Dans le cas de la machine, il faudra également intervenir sur la recette du kernel pour surcharger la variable COMPATIBLE_MACHINE.

Recettes et image

Les variables lues dans toute cette série de fichiers « .conf » sont globales, et peuvent être surchargées au fur et à mesure de leurs initialisations. L’initialisation la plus faible est celle de l’opérateur « ??= » puis vient l’initialisation « ?= » suivie de « = » et finalement l’override « :forcevariable » .

Une fois cette phase d’initialisation terminée, Bitbake va lire le contenu des différents fichiers de recette, en chargeant les variables dans des contextes indépendants pour chaque recette. Par exemple la variable SRC_URI est spécifique pour chaque package. Chaque fichier .bb renseigne sa propre instance de cette variable qui peut éventuellement être complétée dans les .bbappend du même package.

Toutes les recettes sont ainsi lues, incluant éventuellement des fichiers .inc. Dans le contexte de chaque recette sont également ajoutées les méthodes et les variables définies dans les fichiers .bbclass dont elle hérite.

Une fois les recettes chargées en mémoire, bitbake est prêt à commencer le build proprement dit. En cherchant la plupart du temps à produire une recette d’image, en suivant récursivement ses dépendances. Parfois on ne veut produire qu’un seul package (et ses dépendances bien sûr).

Conclusion

Nous avons examinés la liste des fichiers de configuration de bitbake et surtout l’ordre dans lequel ils sont lus. Ceci nous permet d’ajuster notre production de plusieurs manières :

  • en fournissant un fichier initialement absent, plus précisément site.conf ;
  • en complétant et modifiant un fichier fourni par Yocto comme local.conf ;
  • en fournissant une alternative aux fichier <distro>.conf et <machine>.conf se trouvant dans les layers intégrés dans notre image ;
  • et bien sûr en créant une recette <image>.bb personnalisée et en ajustant les recettes fournies grâce à des .bbappend.

Dans le prochain article de cette petite série, nous étudierons les variables principales contenues dans ces fichiers de configuration.

Pour en savoir plus et mettre en pratique, n’hésitez à 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