Bitbake: meccanismi
Come abbiamo già anticipato, bitbake definisce i seguenti formati di file:
.bb.bbappend.bbclass.conf.inc
I file di tipo .bb* e .inc possono contenere
variabili e funzioni bitbake,
mentre i .conf possono contenere
solo variabili bitbake.
Uno dei principi su cui si basa bitbake è il riutilizzo della logica e per farlo implementa i seguenti meccanismi:
includedi file.incinheritdi file.bbclass
Per farla breve,
include rappresenta una “inclusione piatta”
come accade in linguaggio C,
mentre inherit è più complesso
e implementa delle logiche di ereditarietà.
Una buona prassi è quella di utilizzare
include per file che contengono dati in comune
e inherit per logiche (funzioni, override, …)
che possono essere riutilizzate.
Un singolo recipe può essere quindi
realizzato a partire da un file .bb
in cui vengono inclusi file .inc
e anche ereditate delle .bbclass.
In aggiunta a questo esistono anche
i .bbappend, ovvero delle porzioni
di recipe che vanno ad aggiungersi
al .bb di partenza.
Questi permettono di andare a modificare
un qualsiasi .bb senza dover modificare
il file originale.
Può sembrare un meccanismo contorto,
ma permette ad altri sviluppatori
di apportare modifiche puntuali
su un recipe senza farsi carico
di mantenere un fork del recipe originale.
Nel caso il .bb venga aggiornato,
è molto probabile che il .bbappend
sia ancora utilizzabile.
Questo meccanismo nasce dall’esigenza
di permettere a layer differenti
di poter apportare modifiche alla
generazione di un package,
in quanto questo potrebbe necessitare
di configurazioni diverse
in base all’ hardware effetivamente
presente nella scheda scelta
o in base a diverse finalità di uso.
Le modifiche possono riguardare
qualsiasi fase di build del recipe,
quindi sia a livello di compilazione,
sia a livello di installazione di ulteriori
dipendenze, che tutto il resto.
include / require
Per riutilizzare un qualsiasi tipo di logica,
evitando di fare “copia-incolla”,
è possibile utilizzare le istruzioni
include o require.
Permettono di “inglobare” un intero file
in modo molto simile al #include in linguaggio C.
L’unica differenza tra i due è che
require genera un errore se non trova il file specificato,
mentre include no.
Un esempio di utilizzo nel layer meta:
meta
├── classes-global
├── classes-recipe
├── classes
├── conf
│ ├── distro
│ │ ├── include
│ │ │ ├── default-providers.inc
│ │ │ ├── default-versions.inc
│ │ │ ├── ...
│ │ │ ├── time64.inc
│ │ │ ├── tclibc-baremetal.inc
│ │ │ ├── tclibc-glibc.inc
│ │ │ └── tclibc-musl.inc
│ │ └── defaultsetup.conf
│ │
│ └── layer.conf
├── recipes-bsp
└── ... 1include conf/distro/include/default-providers.inc
2include conf/distro/include/default-versions.inc
3include conf/distro/include/default-distrovars.inc
4include conf/distro/include/maintainers.inc
5include conf/distro/include/time64.inc
6require conf/distro/include/tcmode-${TCMODE}.inc
7require conf/distro/include/tclibc-${TCLIBC}.inc
8
9require conf/distro/include/uninative-flags.inc
10
11# Allow single libc distros to disable this code
12TCLIBCAPPEND ?= "-${TCLIBC}"
13TMPDIR .= "${TCLIBCAPPEND}"Osserviamo che i path sono definiti a partire dalla directory del layer, questo perchè, come vedremo, all’ interno di un layer possiamo individuare i file tramite dei percorsi relativi.
inherit class
Il layer meta fornisce già una quantità enorme
di .bbclass che spaziano da automazioni
per generare file di log relativi alla build del progetto,
fino ad automazioni per gestire la compilazione di recipe tramite cmake.
Nella documentazione ufficiale
troviamo qualche esempio tali classi:
- buildstats
- cargo
- cmake
- image-container
- kernel
- toolchain-scripts
- update-rc.d
Se il nostro recipe si occupa di costruire
un applicativo basato su cmake,
tramite un inherit cmake
possiamo quindi evitare
di dover implementare i task bitbake
do_configure, do_compile e do_install
in quanto cmake.bbclass si occupa già
di implementare tale logica.
Come comportamento di default,
cmake.bbclass si occupa
di lanciare cmake all
compilando il progetto presente nella directory S
dentro la directory di build B
ed infine eseguire cmake install
posizionando i file di output dentro
la directory fakeroot D.
Inoltre viene automaticamente
impostata la dipendenza del recipe
rispetto il recipe cmake-native.
Tramite le variabili
OECMAKE_TARGET_INSTALL
OECMAKE_TARGET_COMPILE
OECMAKE_GENERATOR
EXTRA_OECMAKE
possiamo modificare il processo.
bbappend
Un file .bbappend non può esistere da solo
all’interno del progetto, ma deve avere
almeno un relativo file .bb.
Non è necessario che questi si trovino nel medesimo layer.
L’unico vincolo è che abbiano lo stesso nome e versione del recipe.
Ricordiamo che un recipe è identificato su disco
tramite un file del tipo:
busybox_1.36.1.bb
busybox 1.36.1
↑ ↑
nome versione Quindi se vogliamo creare un append a questo recipe dobbiamo utilizzare un file del tipo:
busybox_1.36.1.bbappendbitbake permette di utilizzare il carattere %
come wildcard per la versione del recipe,
quindi è valido anche:
busybox_%.bbappendinvece non è valido il semplice:
busybox.bbappend [NON VALIDO]Ogni .bbappend è valutato appunto
come una aggiunta al .bb originale
e ai .bbappend precedenti.
L’ordine dipende dal parsing dei recipe
e dall’ordine di priorità dei layer.
conclusioni
.inc e .bbclass servono a risparmiare tempo nella scrittura di un recipe,
mentre .bbappend serve per dare flessibilità nella configurazione.
Ok, se ti sembra tutto molto confuso, allora aspetta di arrivare alla fine e poi ne parliamo. Per il momento abbiamo solo planato sopra ai concetti, ma più avanti dovremo capire come utilizzarli effettivamente. Cosa? Quali menti malate si sono inventate tutto questo delirio? Per il momento non pensarci, un giorno ti sarà tutto più chiaro.