In diesem Kapitel wird die Erstellung
und Konfiguration
der angepassten eingebettete Linux Distribution
für Flutter
mit dem Yocto Projekt
beschrieben.

## Einrichtung der Build-Umgebung

Zur einfacheren Handhabung wurde für die Build-Umgebung
der Docker-Container _crops/poky:ubuntu-22.04_ genutzt.
Crops steht für "CROss PlatformS" und ist ein Community Projekt
mit dem Ziel, die Entwicklung von Yocto Distributionen zu vereinfachen,
das Projekt ist auf GitHub zu finden [@Crops].
Docker ist ein Open-Source-Projekt, welches die Bereitstellung
von Anwendungen in Containern ermöglicht. In diesen Containern kann ein
komplettes Betriebssystem mit allen Abhängigkeiten und Anwendungen
abgebildet werden. In diesem Fall werden in dem Container alle
notwendigen Werkzeuge und Abhängigkeiten für die Erstellung der Yocto-Distribution
bereitgestellt.

Die Ordnerstruktur der Build-Umgebung ist in Abbildung \ref{buildEnvironment} dargestellt
mit den wichtigsten Dateien zur Konfiguration und Steuerung des Build-Prozesses. Diese
Dateien werden im Folgenden genauer erläutert.

\begin{figure}[H]
\caption{Die wichtigsten Dateien und Verzeichnisse der Build-Umgebung}
\label{buildEnvironment}
\centering
\begin{minipage}{7cm}
\dirtree{%
.1 crops-yocto/.
.2 build/.
.3 ....
.3 conf/.
.4 bblayers.conf.
.4 local.conf.
.2 poky/.
.3 ....
.3 bitbake/.
.3 oe-init-build-env.
.2 run\char`\_crops.sh.
.2 Makefile.
}
\end{minipage}
\end{figure}

In dem Verzeichnis _poky_ befinden sich alle Dateien zur Erstellung
der Linux Distribution. Poky ist der Name einer Referenz-Distribution
des Yocto Projekts und dient als Basis für die Erstellung von
eigenen Distributionen [@TechnicalOverviewa]. In dem Projekt wurde
die Version 4.0.13 von Poky genutzt, welche den Codenamen "kirkstone"
trägt und zum Zeitpunkt der Erstellung des Projektes die aktuellste
LTS (Long-Term-Support) Version war. Alle zwei Jahre wird eine neue
LTS-Version veröffentlicht und jedes halbe Jahr eine neue Stable-Version,
welche für ein halbes Jahr unterstützt wird [@ReleasesYoctoProject]. Das
Poky Projekt ist auf GitHub veröffentlicht und Version 4.0.13 ist
unter dem Commit `e6076b6269d8d6868a9dd7565dab228e6d1ce2a2` zu finden [@YoctoprojectPoky2024].

Poky beinhaltet
BitBake, das Build-System vom Yocto Projekt, welches speziell
für die Erstellung von Linux Distributionen
für eingebettete Systeme entwickelt wurde. BitBake führt
Aufgaben gemäß den bereitgestellten Metadaten aus. Metadaten
werden in Rezept-Dateien (.bb) und zugehörigen Rezepten (.bbappend),
Konfigurationsdateien (.conf) und zugrunde liegenden Include-Dateien
(.inc) sowie Klassendateien (.bbclass) definiert. Die Metadaten
liefern BitBake Anweisungen dazu, welche Schritte ausgeführt werden
müssen und welche Abhängigkeiten bestehen. BitBake wurde von der Paketverwaltung
Portage von der quellbasierten Linux-Distribution Gentoo
inspiriert und arbeitet gleichermaßen quellbasiert. Das bedeutet, dass
der Quellcode der Software heruntergeladen wird und speziell für
die Zielplattform kompiliert wird anstatt wie bei alltagsüblichen
Betriebssystemen wie Windows, macOS oder Ubuntu Linux binäre Dateien zu installieren,
welche vorkompiliert sind. In den Schritten bei der Ausführun von BitBake wird deshalb zuerst
ein Cross-Compiler erstellt, um den Quellcode für die Zielplattform
zu kompilieren. Danach werden alle notwendigen Werkzeuge für die
Build-Umgebung erstellt und dann wird der Quellcode für die Zielplattform
kompiliert. Zuletzt werden die erstellten Dateien in ein Image
zusammengefasst, dies bildet dann die fertige Distribution, welche
auf dem Zielsystem ausgeführt werden kann. [@OverviewBitbakeDev]

Rezepte werden auch in dem _poky_ Verzeichnis in den Ordnern abgespeichert,
welche mit "_meta_" beginnen, diese werden
Meta-Layer genannt. Welche Meta-Layers genutzt werden,
wird in der Datei _bblayers.conf_ für BitBake festgelegt und in
Kapitel \ref{yoctoLayers} werden die genutzten Meta-Layers des
Projekts durchgegangen. In der Datei _local.conf_ wird konfiguriert,
welche Rezepte genutzt werden
und mithilfe von Variablen können die Rezepte angepasst werden. In dem
Projekt wird in _local.conf_ alles konfiguriert, was für die Erstellung
der eingebetteten Linux Distribution mit Flutter notwendig ist und es
wurden zwei Beispiel-Konfigurationen erstellt, einmal den Raspberry Pi 4 und
den Raspberry Pi 0 2W.

Die Datei _run_crops.sh_ ist ein Shell-Skript, welcher als Hilfsskript
die Nutzung des Docker-Containers vereinfacht.
Der Code des Skripts entstammt eines GitHub Projektes von Yusuke Mitsuki [@yusukemitsukiHelperScriptRuna].
Mit dem Skript wird der Docker-Container gestartet und die Build-Umgebung
aus der Datei _oe-init-build-env_ wird für BitBake initialisiert. Zusätzlich wird
das Verzeichnis, in dem das Skript ausgeführt wird, in den Docker-Container
eingehängt. Das bedeutet, dass alle Änderungen, die durch den Docker-Container
gemacht werden lokal in dem _crops-yocto_ Verzeichnis gemacht werden. In dem
_build_ Verzeichnis sind dadurch alle fertigen Images von BitBake zugreifbar
für den Nutzer, der das Skript ausführt. Die Dateien werden außerhalb der
Docker-Umgebung abgespeichert.

Um die Build-Umgebung des Projekts so einfach wie möglich bedienbar zu machen,
wurde ein _Makefile_ erstellt, welche die wichtigsten Befehle für die Erstellung
der Distribution zur Verfügung stellt. In Auflistung \ref{makeFile} wird der
Inhalt der Makefile-Datei abgebildet und im danach wird der Inhalt erklärt.

```{.bash .number-lines caption="Inhalt der Makefile-Datei" captionpos=t label=makeFile}
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))

all:
	./run_crops.sh bitbake core-image-full-cmdline

flash-pi4:
	sudo dd if=${ROOT_DIR}build/tmp/deploy/images/raspberrypi4-64/core-image-full-cmdline-raspberrypi4-64.rpi-sdimg of=/dev/sda

flash-zero:
	sudo dd if=${ROOT_DIR}build/tmp/deploy/images/raspberrypi0-2w-64/core-image-full-cmdline-raspberrypi0-2w-64.rpi-sdimg of=/dev/sda

clean-all:
	./run_crops.sh bitbake -c cleanall core-image-full-cmdline

clean-flutter-elinux:
	./run_crops.sh bitbake -c clean flutter-elinux

clean-flutter-pi:
	./run_crops.sh bitbake -c clean flutter-pi

clean-flutter-sdk:
	./run_crops.sh bitbake flutter-sdk-native -cdo_cleanall

clean-flutter-engine:
	./run_crops.sh bitbake flutter-engine -cdo_cleanall
```

Mit dem Befehl _make_ wird mit dem _run_crops.sh_ Skript der Docker-Container
gestartet und BitBake mit dem Befehl _bitbake core-image-full-cmdline_ ausgeführt
und somit die komplette Distribution samt Image für die konfigurierte
Zielplattform erstellt. Für BitBake gibt es verschiedene Image Varianten,
_core-image-full-cmdline_ ist eine davon und wurde für das Projekt gewählt,
weil es ein reines Konsolen-Image ist, welches zusätzlich die komplette
Hardware des Zielsystems unterstützt (deshalb "full") [@ImagesYoctoProject].
Ein Konsolen-Image ist ein Image, welches nur eine Kommandozeile
zur Verfügung stellt und keine Desktop-Umgebung. Das Image wurde gewählt,
weil Flutter-Pi keine Abhängigkeiten von Desktop-Umgebungen wie X11 oder Wayland
hat und somit ein Konsole-Image ausreichend ist. Für Flutter-Auto wurden alle
Wayland Abhängigkeiten manuell in der _local.conf_ Datei hinzugefügt.
Der erste Build dauert je nach der Leistung des Systems unterschiedlich
lang, mit einem AMD Ryzen 7 6800U dauerte der Build ungefähr 5 Stunden und es werden
mit beiden Builds für beide Test-Systeme ungefähr 80 GB an Speicherplatz benötigt. In einem Test
konnte festgestellt werden, dass der Build-Prozess aufgrund eines Fehlers abbrechen kann, bei dem
eine Quelle aus dem Internet nicht gefunden werden kann. Es kann sein, dass der Fehler nur aufgrund
eines kurzzeitigen Netzwerkfehlers auftrat, falls es jedoch passiert, muss der Prozess
nur neugestartet werden. Der Build wird dann an der Stelle fortgesetzt,
an der er abgebrochen wurde und es sollte keine Probleme geben.
Neue Builds dauern später nur wenige Minuten, weil nur die geänderten
Dateien neu kompiliert werden müssen.

Nachdem das Image für die SD-Karte erstellt wurde, kann es auf die SD-Karte
geschrieben werden. Dafür gibt es zwei Make-Befehle, _flash-pi4_ und _flash-zero_,
welche entweder das Image für den Raspberry Pi 4 oder den Raspberry Pi 0 2W auf
die SD-Karte schreiben. Dazu wird das bei unixoiden Systemen wie Linux und macOS eingebaute _dd_
Kommandozeilen-Werkzeug genutzt, welches Daten von einem Speichermedium auf ein
anderes kopiert. Dabei ist wichtig zu beachten, dass der Pfad zur SD-Karte in der
Makefile-Datei angepasst werden muss, da der Pfad _/dev/sda_ nur ein Beispiel ist
und je nach System die SD-Karte an einem anderen Pfad angeschlossen ist.

Zuletzt gibt es noch eine Reihe von Befehlen, um die Build-Umgebung zu säubern,
diese fangen mit _clean_ an und der einzige Befehl der hiervon häufig verwendet
werden muss ist _clean-flutter-elinux_. Dieser Befehl löscht alle gecachten
Dateien vom Flutter-eLinux Projekt, dies ist immer dann notwendig, wenn Änderungen
an dem Projekt gemacht wurden und eine neue Version von Flutter-eLinux genutzt
werden soll. Ansonsten gibt es einen Fehler beim Bauen der Distribution, welcher
jedoch sehr verbos ist und nach vielen Versuchen konnte herausgefunden werden,
dass das Löschen der gecachten Dateien das Problem behebt.
Im folgenden Kapitel werden die Meta-Layer des Projekts genauer beschrieben und
darin wird erklärt wie Flutter-eLinux konfiguriert wurde.

## Genutzte Meta-Layer {#yoctoLayers}

In diesem Projekt werden folgende Meta-Layer aus anderen Quellen genutzt,
diese Layer wurden in dem Projekt als Git-Submodule hinzugefügt und sind
auf die jeweiligen Commits festgesetzt worden, um eine reproduzierbare
Erstellung der Distribution zu gewährleisten. Bei der Nutzung von
Meta-Layers ist es zudem wichtig, immer die Branch des Meta-Layers auf
die Version des Yocto Projekts zu setzen, in diesem Fall wurde
immer "kirkstone" genutzt.

\begin{center}
\begin{table}[h]
\caption{Genutzte Meta-Layer aus anderen Quellen und Commits}
\resizebox{\textwidth}{!}{%
\begin{tabular}{|l|l|}
\hline
Git Adresse des Meta-Layers & Commit \\ \hline
https://github.com/kraj/meta-clang & 312ff1c39b1bf5d35c0321e873417eb013cea477 \\ \hline
https://github.com/meta-flutter/meta-flutter & 82e167a7f13161a4ee9c5a426f13df79987d1055 \\ \hline
https://github.com/openembedded/meta-openembedded & fda737ec0cc1d2a5217548a560074a8e4d5ec580 \\ \hline
https://github.com/agherzan/meta-raspberrypi & 9dc6673d41044f1174551120ce63501421dbcd85 \\ \hline
https://github.com/jwinarske/meta-vulkan & ceb47bd0ed2a9f657fdae48a901e8a41ba697e74 \\ \hline
https://codeberg.org/flk/meta-wayland & cb22939f751c74baa51d9474ba6e8ba647e99756 \\ \hline
\end{tabular}%
}
\end{table}
\end{center}

Das Meta-Layer "meta-vulkan" wurde nur getestet und nicht weiter genutzt, es
stammt von den Machern des "meta-flutter" Layers und kann in Zukunft
genutzt werden um die Vulkan-Unterstützung von Flutter zu testen. Der
Build der Vulkan Treiber für den Raspberry Pi 4 war im einem Test jedoch nicht erfolgreich.

Manche der Layer sind Sammel-Layer und enthalten mehrere Layers in sich und neben
den Standard-Layern von Yocto und den Layern aus anderen Quellen wurde noch
ein eigenes Layer "_meta-flutter-elinux_" erstellt, welches angepasste Rezepte
für Flutter-eLinux enthält. In der Auflistung \ref{bbLayers} wird der Inhalt
der _bblayers.conf_ Datei abgebildet, welche die genutzten Meta-layers
für BitBake festlegt. Diese Layer wurden in dem Projekt genutzt für die
angepasste Linux Distribution verwendet.

```{.bash .number-lines caption="Inhalt der bblayers.conf Datei" captionpos=t label=bbLayers}
YOCTOROOT = "${@os.path.abspath(os.path.join("${TOPDIR}", os.pardir))}"

BBLAYERS ?= " \
  ${YOCTOROOT}/poky/meta \
  ${YOCTOROOT}/poky/meta-poky \
  ${YOCTOROOT}/poky/meta-yocto-bsp \
  ${YOCTOROOT}/poky/meta-clang \
  ${YOCTOROOT}/poky/meta-raspberrypi \
  ${YOCTOROOT}/poky/meta-openembedded/meta-oe \
  ${YOCTOROOT}/poky/meta-openembedded/meta-python \
  ${YOCTOROOT}/poky/meta-openembedded/meta-networking \
  ${YOCTOROOT}/poky/meta-flutter \
  ${YOCTOROOT}/poky/meta-wayland \
  ${YOCTOROOT}/poky/meta-flutter-apps \
  ${YOCTOROOT}/poky/meta-flutter-elinux \
  "
```

Die Layer "meta", "meta-poky", "meta-yocto-bsp", "meta-clang", "meta-oe",
"meta-python" und "meta-networking" sind Standard-Layer welche in dem
Projekt allein für nötige Abhängigkeiten genutzt werden. Auf diese
wird deshalb nicht genauer eingegangen.

### Meta-Flutter

Das _meta-flutter_ Layer ist ein Sammel-Layer und enthält Rezepte für
die Flutter Engine, Flutter SDK, Flutter Beispiel Apps und die verschiedenen
Embedder für Flutter zur Nutzung im eingebetteten Linux. Das Layer
wird von dem Hauptentwickler Joel Winarske gepflegt, welcher bei
Toyota Connected North America (TCNA) arbeitet und es wurde
unter der MIT Lizenz unter GitHub veröffentlicht [@joelwinarskeMetaflutterMetaflutter2024].

Aus dem Layer wird die Flutter Engine zusammen mit den zwei Embeddern
Flutter-Pi und Flutter-Auto genutzt.

### Meta-Flutter-Apps

Das _meta-flutter-apps_ Layer ist eine Kopie aus dem _meta-flutter-apps_ innerhalb des
_meta-flutter_ Layers, in der das Rezept für Flutter-eLinux hinzugefügt wurde.
Der Ordner wurde kopiert, da _meta-flutter_ als Submodul hinzugefügt wurde und
nicht direkt bearbeitet werden sollte.

Das Rezept für Flutter-eLinux ist unter _poky/meta-flutter-apps/recipes-graphics/flutter-apps/third-party/flutter-elinux_git.bb_
zu finden und enthält nur Variablen, mit dem die Flutter-App angepasst werden kann.
In der Variable _SRC_URI_ werden alle Git Adressen des Flutter-eLinux Projekts und
seinen Submodulen definiert und es wird ein Nutzername mit Passwort gesetzt um
die Quellen erreichen zu können, da die Git Adressen privat sind.
Die Commits werden in "SRCREV" Variablen definitert. "SRCREV" steht für das Hauptprojekt,
"SRCREV_vkml" für das "virtual_keyboard_multi_language" Paket und "SRCREV_rtc" für das
"real_time_graph" Paket. Wenn diese Commits geändert werden um eine neue Version
von Flutter-eLinux zu nutzen, muss wie erwähnt vor dem nächsten Build
der Befehl `make clean-flutter-elinux` ausgeführt werden.

### Meta-Wayland

Das _meta-wayland_ Layer ist ein Sammel-Layer für Wayland und enthält Rezepte
für viele Wayland Komponenten. Aus dem Layer wurde der Wayland Kiosk Cage
verwendet, welcher mit Flutter-Auto genutzt wurde. Cage ist ein Open-Source
Projekt, welches auf GitHub veröffentlicht wurde [@CagekioskCage2024].

Bevor Cage verwendet wurde, wurde versucht Weston als Wayland-Desktop zu nutzen,
Weston ist ein Referenz Wayland-Compositor der auf GitLab veröffentlicht
wurde [@WaylandWestonGitLab2024]. Doch der Kiosk Modus von Weston ist zu limitiert und braucht zwingend einen
Output-Namen des Bildschirms, welcher jedoch bei verschiedenen eingebetteten
Systemen dann nicht immer gleich wäre. Im Test konnte Weston auch nie erfolgreich
im Kiosk Modus mit einem der Flutter Embedder gestartet werden. Cage hingegen
erscheint einfacher in der Konfiguration und konnte erfolgreich die Embedder
starten. Bei Weston ist jedoch zu beachten, dass im normalen Desktop-Modus
die Flutter Embedder auf 30 Bilder pro Sekunde limitiert sind, obwohl der
Desktop in 60Hz läuft. Hier ist nicht klar warum es zu diesem Bug kommt. In der _local.conf_
kann Weston in der _IMAGE_INSTALL_ Variable hinzugefügt werden, wenn es getestet werden soll.
Es sollte dabei auch darauf geachtet werden, dass keiner der Embedder mehr automatisch startet (im Folgenden
wird erklärt wie die Embedder konfiguriert sind).

### Meta-Flutter-eLinux

In _meta-flutter-elinux_ wurden speziell für das Projekt notwendige Rezepte erstellt.
In Abbildung \ref{metaFlutterElinux} ist die Ordnerstruktur des Layers dargestellt.

\begin{figure}[H]
\caption{Ordnerstruktur des meta-flutter-elinux Layers}
\label{metaFlutterElinux}
\centering
\begin{minipage}{10cm}
\dirtree{%
.1 meta-flutter-elinux/.
.2 recipes-core/.
.3 custom-scripts/.
.4 files/.
.5 flutter-auto-launch/.
.4 flutter-auto-launch\char`\_1.00.bb.
    .3 flutter-elinux-rules/.
    .4 files/.
    .5 90-interfaces.rules.
    .4 flutter-elinux-rules\char`\_1.00.bb.
.3 flutter-user/.
.4 flutter-user\char`\_1.00.bb.
    .3 systemd/.
    .4 files/.
    .5 flutter-auto.service.
    .5 flutter-pi.service.
    .4 flutter-auto-service\char`\_1.00.bb.
.4 flutter-pi-service\char`\_1.00.bb.
    .4 systemd\char`\_\%.bbappend.
.3 systemd-conf/.
.4 files/.
.5 en.network.
.5 eth.network.
.5 wlan.network.
.4 systemd-conf\char`\_\%.bbappend.
}
\end{minipage}
\end{figure}

Das Rezept _flutter-elinux-rules_ enthält die Udev-Regeln, welche für die
Kommunikation zwischen Flutter-eLinux und dem Host-System notwendig sind. In dieser
wird definiert, dass die Gruppe "gpio" Zugriff auf die GPIO-Pins des Raspberry Pi
bekommt und die Gruppe "spidev" Zugriff auf die SPI-Schnittstelle.
Die Regeln werden in der Datei _90-interfaces.rules_ definiert. Nach einer längeren
Recherche konnten diese Regeln in einer Maillist von Yocto gefunden werden. In dieser
wurde eine Beispielkonfiguration mit den GPIO und SPI Regeln von Markus W genannt [@Metaraspberrypi].
Das _flutter-user_ Rezept erzeugt den Nutzer _user1_, welcher Teil der Gruppen
_video_, _input_, _gpio_ und _spidev_ ist. Die Gruppen _video_ und _input_ sind
für die Nutzung des Bildschirms und der Touch-Eingabe notwendig. Nur nachdem die
Udev-Regeln und der Nutzer erstellt wurden, kann Flutter-eLinux korrekt genutzt werden.
Vorher funktionierte das Ansprechen der GPIO-Pins und der SPI-Schnittstelle nicht.
Der Nutzer war auch notwendig, weil der Flutter-Auto Embedder nur mit Wayland
gestartet werden kann und Wayland kann nicht als Root-Nutzer gestartet werden.

In dem _systemd-conf_ und _systemd_ Verzeichnis wurde die Netzwerkkonfiguration
definiert, welche aus einer Anleitung dazu vom Mender Hub Forum stammt [@drewmoseleyHowConfigureNetworking2023].
Es kam auch die Idee Systemd-Service-Dateien zu nutzen, um die Embedder mit Flutter-eLinux
automatisch beim Start des Systems zu starten. Dazu wurden die Dateien _flutter-auto.service_
und _flutter-pi.service_ erstellt, welche mit den Rezepten _flutter-auto-service_ und
_flutter-pi-service_ jeweils in der _local.conf_ aktiviert werden können in der
Variable _IMAGE_INSTALL_. Dabei ist wichtig immer nur einen der beiden Embedder zu
aktivieren. Der Systemd-Service wurde zusätzlich auch so konfiguriert, dass der Service bei
einem Absturz automatisch neu gestartet wird. In der Praxis konnte bestätigt werden, dass
in einem Absturz beim Raspberry Pi 0 2W der Embedder automatisch neu gestartet wurde.

<!-- ## System Voraussetzungen

https://docs.yoctoproject.org/4.0.13/ref-manual/system-requirements.html

Unterstützte Linux Distributionen:

- Ubuntu 20.04 (LTS)
- Ubuntu 22.04 (LTS)
- Fedora 37
- Debian GNU/Linux 11.x (Bullseye)
- AlmaLinux 8.8 -->

<!-- \pagebreak

## Yocto Project

Kein source-code, nur meta daten.
Die Regeln, wie der Source-Code gebaut wird,
werden in Rezepten festgelegt.

docker als build-umgebung.
https://hub.docker.com/r/crops/poky

poky = yocto.
Yocto Project basierend auf Poky Linux.
Ausgesprochen "Pocky" wie das japanische Knabberzeug.

Alle 6 Monate neue Version.
Alle 2 Jahre Long-Term-Support Version.

Distro: How I want to put my system together.
Machine: the board i want to build for.
Image: the selection of packages i want.

build cross-compiler.
tools for build time.
compile code for target machine.

### Layers

Layer contains bunch of recipes.

3 layers:
bsp: board support package
defines a machine and related board-specific packages
contains conf/machine/[MACHINE].conf

distribution: defines a DISTRO such as Poky
contains conf/distro/[DISTRO].conf

Software: everything else
contains neither conf/machine/[MACHINE].conf nor conf/distro/[DISTRO].conf
libraries, e.g. qt5
languages, e.g. Java
tools, e.g. virtualisation or selinux

### Recipes

contain instructions on how to fetch, configure, compile and install a software component
the body contains BitBake metadata (assignment of variables, mostly); the tasks are written
in shell script or Python
Recipe files have a suffix .bb
may be extended with append recipes with .bbappend suffix

majority of recipes produce packages.
/tmp/deploy/rpm/..
often one recipe produces several packages.

IMAGE_INSTALL:append

### Images

core-image-base: A console-only image that fully supports the target device hardware.
core-image-full-cmdline: A console-only image with more full-featured Linux system functionality installed.
core-image-minimal: A small image just capable of allowing a device to boot.
core-image-weston: A very basic Wayland image with a terminal. This image provides the
Wayland protocol libraries and the reference Weston compositor. For more information,
see the “Using Wayland and Weston” section in the Yocto Project Development Tasks Manual.

\begin{figure}[h]
\caption{Example caption}
\centering
\begin{minipage}{7cm}
\dirtree{%
.1 poky/.
.2 meta/.
.2 meta-poky/.
.2 meta-yocto-bsp/.
.2 meta-selftest/.
.2 meta-skeleton/.
.2 mea-clang/.
.2 meta-flutter/.
.2 meta-flutter-apps/.
.2 meta-flutter-elinux/.
.2 meta-openembedded/.
.2 meta-raspberrypi/.
.2 meta-wayland/.
.2 meta-vulkan/.
}
\end{minipage}
\end{figure}

\begin{figure}[h]
\caption{Example caption}
\centering
\begin{minipage}{10cm}
\dirtree{%
.1 meta-flutter-apps/.
.2 recipes-graphics/.
.3 flutter-apps/.
.4 third-party/.
.5 flutter-elinux\char`\_git.bb/.
.5 flutter-wonders\char`\_git.bb/.
}
\end{minipage}
\end{figure} -->
