Layers

In Yocto i recipe si occupano della gestione di un singolo applicativo o funzionalità, mentre i layer sono semplicemente dei raccoglitori di molteplici recipe. L’idea alla base di un layer Yocto è che questo deve rendere praticamente “plug and play” l’aggiunta di funzionalità molto complesse ad un generico sistema. Una buona prassi infatti è quella di costruire un progetto basandosi su almeno 3 layer distinti:

  • hardware specifico
  • funzionalità comuni
  • applicativi specifici

Questo con l’obiettivo di modularizzare il progetto e permettere il riuso di un layer in progetti diversi, senza incappare in problematiche di conflitti tra recipe.

In Yocto queste sono proprio le 3 tipologie di layer:

  • BSP
  • Distro
  • Application

Un singolo layer può mescolare molteplici tipologie, ma appunto non è una buona prassi.

BSP

BSP è l’ acronimo di Board Support Package (documentazione ufficiale). L’obiettivo di questo layer è di occuparsi di tutte le magagne associate ad una determinata scheda o architettura. Ad esempio esistono BSP layer per:

Per supportare una determinata scheda è normale il dovere utilizzare molteplici layer BSP in “sequenza”. Se molteplici schede utilizzano processori ARM, ha senso che le funzionalità generiche di un processore ARM siano racchiuse in proprio layer, mentre le cose più specifiche ad una scheda o processore risiedano in un layer aggiuntivo. Questa è la filosofia di Yocto e, più in generale, di un buon progetto software.

Distro

Distro è associato all’ idea di distribuzione Linux, ovvero una raccolta di strumenti e funzionalità software che ci si aspetta di trovare in un determinato ambiente Linux (documentazione ufficiale). Ad esempio

  • in una distribuzione Debian ci aspettiamo di trovare il package manager apt

  • in una distribuzione desktop ci aspettiamo di trovare un display server come Wayland o X

  • in una qualsiasi distribuzione ci aspettiamo di trovare i classici comandi shell come ls grep e così via

Di base, Linux rappresenta solo il kernel, mentre queste assunzioni riguardano la presenza di pacchetti software installati (e correttamente configurati). Un Distro layer racchiude quindi tutte quelle cose che ci aspettiamo di trovare di base in un sistema Linux. Poi per casi specifici possiamo andare ad aggiungere o rimuovere cose, ma qua stiamo cercando di coprire il buon 80% dei casi.

Software

Questo nome è volutamente generico. Qualsiasi cosa che stiamo vedendo è definibile come software. Pure i layer BSP e Distro possono essere definiti Software. Infatti i layer BSP e Distro sono specifici, mentre Software è molto più generico. È “tutto il resto” (documentazione ufficiale). La grande distinzione è che un layer Software fatto bene deve essere hardware-agnostic.

Ad esempio, un layer Software può implementare:

  • un applicativo complesso come Gnome (meta-gnome)
  • un interprete Python (meta-python)
  • varie utility per creare un web server (meta-webserver)

Questi layer, tra l’altro, sono così generici ed essenziali che fanno parte della raccolta meta-openembedded, chiamata anche oe-extra, perchè non rappresenta il build system open-embedded di per sè, ma aggiunge il supporto per funzionalità estremamente comuni.

Altri esempi di layer Software, che però non fanno parte di oe-extra sono:

dove trovarli

OpenEmbedded fornisce un portale web dove poter trovare quasi tutti i layer Yocto possibili e immaginabili al OpenEmbedded Layer Index.

Per ognuno di questi troviamo dettagli sui recipe contenuti all’interno, su eventuali dipendenze da altri layer, sul livello di “qualità” del layer e molto altro. Il livello di qualità è da intendersi come la quantità di buone prassi che sono state seguite e che quindi garantiscono una buona integrazione del layer all’ interno del build system. In sostanza indica se un layer sia stato pensato per non creare conflitti vari con altri layer (Yocto Project Compatible Layers).

Poi ovviamente possono esistere altri layer disponibili ovunque nel web, ma quelli nel oe index almeno sono stati visionati da qualcuno di esperto.

come sono fatti

Un layer è descritto tramite un file layer.conf che definisce alcune informazioni sul layer e soprattuto definisce i path a cui trovare i vari recipe. Yocto definisce una struttura di precisa di cartelle e file da utilizzare per costruire un layer, ma tutte queste convenzioni sono definite tramite il file layer.conf. La struttura generica è questa:

layer directory
meta-example
 ├── classes
 │    └── example-class.bbclass
 ├── conf
 │    └── layer.conf
 ├── recipes-****
 ├── recipes-****
 └── recipes-****
      ├── example-recipe-1
      └── example-recipe-2
           └── example-recipe-2.bb

ovvero una cartella conf dove configurare il layer e molteplici cartelle recipes- per contenere uno o più recipe.

Un generico layer.conf può essere:

meta-poky/conf/layer.conf
 1# We have a conf and classes directory, add to BBPATH
 2BBPATH =. "${LAYERDIR}:"
 3
 4# We have recipes-* directories, add to BBFILES
 5BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
 6            ${LAYERDIR}/recipes-*/*/*.bbappend"
 7
 8BBFILE_COLLECTIONS += "yocto"
 9BBFILE_PATTERN_yocto = "^${LAYERDIR}/"
10BBFILE_PRIORITY_yocto = "5"
11
12LAYERSERIES_COMPAT_yocto = "scarthgap"
13
14# This should only be incremented on significant changes that will
15# cause compatibility issues with other layers
16LAYERVERSION_yocto = "3"
17
18LAYERDEPENDS_yocto = "core"
19
20REQUIRED_POKY_BBLAYERS_CONF_VERSION = "2"

La prima cosa che avviene è la modifica della variabile BBPATH che è la variabile utilizzata in tutto il build system per definire i percorsi da analizzare. Tramite un immediate prepend viene aggiunto il path definito da LAYERDIR, la quale contiene il valore assoluto del percorso alla cartella del nostro layer. Questa assegnazione è il motivo per cui nei recipe possiamo fare riferimento ad altri file utilizzando il percorso relativo rispetto alla directory del layer stesso.

Successivamente con BBFILE vengono definiti i percorsi in cui bitbake dovrà cercare eventuali file .bb. Questi percorsi sono valutati a partire da un qualsiasi percorso definito in BBPATH. In BBFILE potremmo definire dei percorsi che escono al di fuori del layer, ma questo è decisamente sconsigliato. Sempre qui viene anche decisa la struttura delle cartelle recipes-, che è sempre del tipo:

layer directory
recipes-CATEGORY
 ├── RECIPE-1
 │    └── RECIPE-1.bb
 └── RECIPE-2
      └── RECIPE-2.bbappend

Solitamente per le cartelle recipes- vengono utilizzati dei nomi che sono già presenti nel layer meta, in modo da replicarne la struttura, ad esempio:

meta - layer directory
meta
 ├── conf
 ├── recipes-bsp
 ├── recipes-connectivity
 ├── recipes-core
 └── recipes-kernel

Questa non è una regola ferrea, ma semplicemente una convenzione che permette poi di visualizzare più facilmente le “sovrapposizioni” di molteplici layer. Infatti se un layer presenta un .bb in meta-layer/recipes-core/app.bb, allora la convenzione suggerisce che un diverso layer posizioni un app_%.bbappend al percorso meta-other-layer/recipes-core/app_%.bbappend.

come sono fatti pt.2

Quella che abbiamo appena visto è la struttura di un layer generico e i layer generici sono quelli di tipologia Software. I layer BSP e Distro hanno come unica differenza la presenza di una sottocartella aggiuntiva alla cartella conf.

Se è presente la cartella conf/machine allora il layer è di tipo BSP.

Se è presente la cartella conf/distro allora il layer è di tipo Distro.

E’ possibile utilizzare entrambe le cartelle nello stesso layer, a discapito della modularità di questo. Queste cartelle contengono degli ulteriori file .conf che sfruttano la solita logica di variabili bitbake. Utilizzano variabili che sono usate per pilotare meccanismi molto particolari, come MACHINE_FEATURES e DISTRO_FEATURES, ma li vedremo nelle sezioni dedicate ai layer BSP e Distro. Questa voleva essere solo una premessa.

Un esempio di struttura:

layer directory
meta-example-bsp
 ├── classes
 ├── conf
 │    ├── machine
 │    │    ├── example-board-1.conf
 │    │    └── example-board-2.conf
 │    └── layer.conf
 ├── recipes-****
 ├── recipes-****
 └── recipes-****

Siccome molte definizioni sono spesso comuni a molteplici schede è possibile raggruppare queste definizioni comuni all’interno di file .inc e includerli all’interno dei vari file .conf:

layer directory
meta-example-bsp
 ├── classes
 ├── conf
 │    ├── machine
 │    │    ├── include
 │    │    │    └── common.inc
 │    │    ├── example-board-1.conf
 │    │    └── example-board-2.conf
 │    └── layer.conf
 ├── recipes-****
 ├── recipes-****
 └── recipes-****
meta-example-bsp/conf/machine/example-board-1.conf
1include conf/machine/include/common.inc
2
3BOARDNAME = "board-1"

classi bitbake

Per essere riconosciute devono avere estensione .bbclass ed essere contenute dentro una sottocartella classes della directory del layer. Altre posizioni non sono riconosciute. Un esempio di struttura di un layer con classi bitbake:

layer directory
meta-example
 ├── classes
 │    ├── example-class-1.bbclass
 │    ├── example-class-2.bbclass
 │    └── example-class-3.bbclass
 ├── conf
 ├── recipes-****
 ├── recipes-****
 └── recipes-****

Nel layer meta sono presenti anche le sottocartelle classes-recipe e classes-global, ma per gli altri layer è disponibile solo la presenza o meno della sottocartella classes. Questo a causa di regole “hard-coded” di bitbake.

conclusioni

Bene, se hai iniziato a leggere questo articolo partendo dalle conclusioni ti dò la soddisfazione di ricevere un elenco delle cose utili. Adesso sappiamo:

  • le 3 tipologie di layer
  • come riconoscerli
  • dove cercarli su internet
  • dentro a un layer possiamo usare path relativi
  • come sono organizzati i recipe
  • dove trovare le classi