Yocto Project 5.0(scarthgap)により組み込みAIにも対応できるRaspberry Pi 5向けの Tensorflow Lite × OpenCV × Dockerを備えた自作Linuxディストリビューションをビルドする

組み込みLinuxでエッジAIの開発をしようと思い立った際に、そういえばYoctoってしばらくビルドしてないなぁ...と思ったので、安価に入手できる 「Raspberry Pi 5」に合わせたLinuxディストリビューションをYocto Projectを使ってビルドする 手順をまとめてみました。今回ターゲットに選択したのは、Raspberry Pi 5の8GBモデルです。

https://www.amazon.co.jp/gp/product/B0D2Y13NHR/

![813Do1DbZmL._AC_SX679_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/3eebbb1c-bfb3-ff96-3f23-e3a09605789c.jpeg)

#### 参考にさせていただきました記事

今回は下記の記事を参考にさせていただきました。ありがとうございます。

https://github.com/agherzan/meta-raspberrypi/issues/1312

https://zenn.dev/kobayutapon/articles/30e38cf076a01b

#### 関連記事

<font color="red">**本記事はYocto 4.0.23(kirkstone) × Raspberry Pi 5の組み合わせが非推奨であったことに対する、下記の記事へ向けた対策記事ともなっています。**</font>

https://qiita.com/xtrizeShino/items/9098a0c188ac3b17ad7c

https://qiita.com/xtrizeShino/items/9c4a8cc28198243a7fab

https://qiita.com/xtrizeShino/items/fcfd4491c09570a51cad

# Yocto 5.0 (scarthgap) on Raspberry Pi 5

本記事ではビルド環境となるOSのセットアップから、ビルド環境の構築、ビルド用コンフィグファイルの設定、実際のビルドと実行結果までをまとめました。 **Yocto Project 5.0 (scarthgap) で生成できるRaspberry Pi 5向けLinuxディストリビューションのGUI版のビルドと実行方法、構築したLinuxディストリビューション向けのアプリケーションやカーネルモジュールを作成するためのSDKをインストールする方法を解説します。** 

**<font color="blue">※Yoctoは Yocto 5.1(styhead)が最新ですが、2024/12/30時点ではBSPである「meta-raspberrypi」に「Yocto 5.1(styhead)」のブランチがなく、「Yocto 5.0(scarthgap)」のブランチのみが存在したため今回はscarthgapを選択しました。</font>**

https://docs.yoctoproject.org/next/migration-guides/release-5.0.html

# 組み込みAI向けLinuxディストリビューション 

今回はGUIに加えて、以下の機能を備え、組み込みプラットフォームである Raspberry Pi 5上で組み込みAIのベースとして動作できる組み込みAI向けLinuxディストリビューションを構築してみます。試してみたのは以下のLayerですが、 **今回の記事では以下でNGとしているレイヤーは、ビルドエラーが発生したため除外しました。Yocto 4.0.23(kirkstone)ではビルドできていたRaspberry Pi 5 AI Kitを組み込めないのは残念ですね...(meta-hailoはi.MX向けにメンテされているようなので仕方ないのですが)**

- Yocto 5.0.5(scarthgap) + meta-raspberrypi
  - Networking <font color="blue">**(OK)**</font>
    - meta-networking 
  - Docker <font color="blue">**(OK)**</font>
    - meta-virtualization
  - Python3 <font color="blue">**(OK)**</font>
    - meta-python
  - OpenCV <font color="blue">**(OK)**</font>
    - opencv, python3-opencv
    - imshowも機能する
  - Tensorflow <font color="red">**(NG)**</font>
    - meta-tensorflow
    - scarthgap向けのブランチなし
  - Tensorflow Lite <font color="blue">**(OK)**</font>
    - meta-tensorflow-lite
  - ONNX runtime <font color="blue">**(OK)**</font>
    - meta-onnxruntime
  - Raspberry Pi 5 AI Kit <font color="red">**(NG)**</font>
    - meta-hailo
    - i.MXにのみ対応している状態
    - scarthgap非対応(yocto 4.x系まで対応)
   - SDKによるカーネルモジュールのビルド <font color="blue">**(OK)**</font>

----

さて、はじめていきましょう。

----


## ビルド環境を構築する

まず、Ubuntu 22.04 LTSをベースとしたビルド環境を構築します。

### Ubuntu 22.04 LTSをインストールする

Yocto 5.0のSystem Requirementに示されているビルド環境を整備します。今回はUbuntu 22.04 LTSを選択しました。USBメモリにインストールイメージを書き込み、標準構成でOSをセットアップします。

https://releases.ubuntu.com/jammy/

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

![Screenshot from 2024-12-25 21-03-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/15a171d6-5d5b-347c-f586-b1c3f736f599.png)

### OSを最新の状態にし、必要なパッケージをインストールする

OSをセットアップした後、下記のコマンドを実行して環境を整備します。

```bash
# 英語(LANG=C)でホームに含まれるディレクトリを再構築する
$ LANG=C xdg-user-dirs-gtk-update 
# 再起動後から利用されるようになる
$ reboot

# すべてのパッケージを最新に更新する
$ sudo apt update
$ sudo apt upgrade

# 日本語入力機能とエディタをインストールする
$ sudo apt install ibus-mozc vim
$ im-config -n ibus

# sshサーバーをインストールする
$ sudo apt install openssh-server
$ sudo systemctl start ssh
$ sudo systemctl enable ssh

```

![Screenshot from 2024-12-25 20-40-53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/155d941f-f413-0805-6c3a-5e8d88b82ce9.png)

### ビルドに必要な依存パッケージをインストールする

Ubuntu 22.04 LTSへYocto Projectのビルドに必要とされるパッケージをインストールします。Yocto Projectのサイトに書かれている内容をそのまま実行すれば問題ありません。

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/50773f45-5e9f-0cb6-85bf-0e5f5cc03ea1.png)

```bash
# System Requirementsで指定されたパッケージをインストールする
$ sudo apt install build-essential chrpath cpio debianutils diffstat file gawk gcc git iputils-ping libacl1 liblz4-tool locales python3 python3-git python3-jinja2 python3-pexpect python3-pip python3-subunit socat texinfo unzip wget xz-utils zstd

# localeにen_US.utf8を追加する
$ locale --all-locales | grep en_US.utf8
# en_US.utf8
$ sudo locale-gen en_US.UTF-8
# Generating locales (this might take a while)...
#   en_US.UTF-8... done
# Generation complete.
```

## Raspberry Pi 5向けのLinuxディストリビューションをビルドするために必要なソースコードを入手する

以上でビルド環境は整いました。次に、Yocto ProjectでLinuxディストリビューションをビルドするために必要なソースコードとビルド用スクリプトを入手しましょう。

### Yocto Project 5.0 をビルドするディレクトリを作成する

今回はYocto Projectの安定版でありRaspberry Pi 5にも対応している **Yocto 5.0.5(scarthgap)** を利用します。まずビルドに備えて作業ディレクトリを作成してください。

```bash
####
# 作業ディレクトリを作成して、移動する
$ mkdir -p ~/scarthgap-work-2024_v1
$ cd ~/scarthgap-work-2024_v1
```

### poky

Yoctoのフレームワークとなるpokyを入手します。 **pokyにはLinuxの基礎となる機能に加えて、ビルド用スクリプトが含まれています。** `git clone`でリポジトリを入手した後に`git checkout`で **scarthgap-5.0.5タグへ切り替え** 、ビルドに必要なリソースを入手します。

https://git.yoctoproject.org/poky

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/4af825c5-4eef-06b9-10ff-2b90dfbedbdd.png)

```bash
$ cd ~/scarthgap-work-2024_v1/
$ pwd
# /home/shino/scarthgap-work-2024_v1
$ git clone git://git.yoctoproject.org/poky
$ cd ./poky
$ git checkout -b scarthgap refs/tags/scarthgap-5.0.5
```

### meta-raspberrypi

「meta-raspberrypi」は **Raspberry Pi向けのBSP(Board Support Package)** を含むLayerです。`git clone`でリポジトリを取得した後に`git checkout`でscarthgap向けのリソースに切り替えます。

https://layers.openembedded.org/layerindex/branch/master/layer/meta-raspberrypi/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/9a702409-55cb-49e6-638d-d7deb895fec3.png)

```bash
$ cd ~/scarthgap-work-2024_v1/poky
$ git clone git://git.yoctoproject.org/meta-raspberrypi
$ cd ./meta-raspberrypi
$ git checkout -b scarthgap origin/scarthgap
```

### meta-openembedded

「meta-openembedded」は **Linuxでよく利用されるアプリケーションやミドルウェア、ライブラリなどが集約されたLayer** です。いくつかのSub-Layerから構成されます。`git clone`でリポジトリを取得した後に`git checkout`でscarthgap向けのリソースに切り替えます。

https://git.openembedded.org/meta-openembedded

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/0f423b31-eb1b-1aed-6966-481d3fa920b9.png)

```bash
$ cd ~/scarthgap-work-2024_v1/poky
$ git clone git://git.openembedded.org/meta-openembedded
$ cd meta-openembedded
$ git checkout -b scarthgap origin/scarthgap
```

### meta-virtualization

「meta-virtualization」は仮想化機能を含むLayerです。近年の開発で広く利用されるDockerもこのLayerに含まれています。 **Dockerを利用することにより、異なるPythonのバージョンのプログラムをカプセル化してシームレスに統合したり、複数のバージョンの依存関係を保持したままシステムに組み上げることなどが可能** になります。`git clone`でリポジトリを取得した後に`git checkout`でscarthgap向けのリソースに切り替えます。

https://layers.openembedded.org/layerindex/branch/master/layer/meta-virtualization/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/dc486b22-eceb-189f-3e27-071196fa2782.png)

https://mickey-happygolucky.hatenablog.com/entry/2023/02/23/070542

```bash
$ cd ~/scarthgap-work-2024_v1/poky
$ git clone git://git.yoctoproject.org/meta-virtualization
$ cd meta-virtualization
$ git checkout -b scarthgap origin/scarthgap
```

### meta-tensorflow <font color="red">【Yocto 5.x向けのbranch無し】</font>

<font color="red">**ビルドしたところ下記のエラーで停止してしまうことを確認しました。
今回ビルドは対象から外します**</font>

```bash
# ERROR: bazel-native-6.0.0-r0 do_patch: Applying patch '0001-HttpDownloader-save-download-tarball-to-distdir.patch' on target directory '/home/shino/scarthgap-work-2024_v1/poky/aiot-build/tmp/work/x86_64-linux/bazel-native/6.0.0/sources'
# CmdError('quilt --quiltrc /home/shino/scarthgap-work-2024_v1/poky/aiot-build/tmp/work/x86_64-linux/bazel-native/6.0.0/recipe-sysroot-native/etc/quiltrc push', 0, "stdout: Applying patch 0001-HttpDownloader-save-download-tarball-to-distdir.patch
```

「meta-tensorflow」は組み込みAIで広く利用されているTensorflowを利用可能とするLayerです。**このTensorflow Layerは、Tensorflowの軽量版であるTensorflow Lite Layerよりも大きいため、本番運用ではTensorflowかTensorflow Liteのいずれかに絞ったほうが良いでしょう。** <font color="red">**なお、meta-tensorflowはmasterがscarthgap/styhead向けですが、変動しておりpatchを当てられないようなので、2024/12/30現在は一旦見送ります。**</font>

https://layers.openembedded.org/layerindex/branch/master/layer/meta-tensorflow/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/6bbc3e09-e47d-8542-46e6-6bfa7a70f98e.png)

```bash
$ cd ~/scarthgap-work-2024_v1/poky
$ git clone git://git.yoctoproject.org/meta-tensorflow
$ cd meta-tensorflow
### masterがscarthgap向けなので、checkoutはしない
### -->> branchが切られるまでビルドに含めない
# $ git checkout -b XXX origin/XXX

# COMPATを確認する
$ grep scarthgap ./conf/layer.conf 
# LAYERSERIES_COMPAT_meta-tensorflow = "scarthgap styhead"
```

#### 下記のようにpatch適用失敗のメッセージが出る

meta-tensorflowをビルドしようとしたところ、下記のエラーが発生しビルドできませんでした。bazelにあてているパッチが対象外となっているようなので、patchだけ外そうかとも思いましたが `meta-tensorflow` ごとビルドから除外します。

```bash
# ERROR: bazel-native-6.0.0-r0 do_patch: Applying patch '0001-HttpDownloader-save-download-tarball-to-distdir.patch' on target directory '/home/shino/scarthgap-work-2024_v1/poky/aiot-build/tmp/work/x86_64-linux/bazel-native/6.0.0/sources'
# CmdError('quilt --quiltrc /home/shino/scarthgap-work-2024_v1/poky/aiot-build/tmp/work/x86_64-linux/bazel-native/6.0.0/recipe-sysroot-native/etc/quiltrc push', 0, "stdout: Applying patch 0001-HttpDownloader-save-download-tarball-to-distdir.patch
# can't find file to patch at input line 19
# Perhaps you used the wrong -p or --strip option?
# The text leading up to this was:
# --------------------------
# |From 28acb4a213938bcb7e55ef3859699091c1f434c0 Mon Sep 17 00:00:00 2001
# |From: Hongxu Jia <hongxu.jia@eng.windriver.com>
# |Date: Thu, 1 Dec 2022 19:32:33 +0800
# |Subject: [PATCH] HttpDownloader: save download tarball to distdir
# |
# |It is helpful for collecting tarball url which supports offline build.
# |
# |Upstream-Status: Inappropriate [oe specific]
# |
# |Signed-off-by: Hongxu Jia <hongxu.jia@eng.windriver.com>
# |---
# | .../bazel/repository/downloader/DownloadManager.java | 12 ++++++++++++
# | 1 file changed, 12 insertions(+)
# |
# |diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java
# |index bf65090..ee30dde 100755
# |--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java
# |+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java
# --------------------------
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/89253d59-ffe2-e383-c110-a42a4ec77c92.png)

https://git.yoctoproject.org/meta-tensorflow/tree/recipes-devtools/bazel/bazel-native_6.0.0.bb?h=master

https://git.yoctoproject.org/meta-tensorflow/tree/recipes-devtools/bazel/files/0001-HttpDownloader-save-download-tarball-to-distdir.patch?h=master

### meta-tensorflow-lite

「meta-tensorflow-lite」は **Tensorflowのうち推論に特化した機能のみを抜き出したミドルウェアTensorflow Liteを利用可能とするLayer** です。`git clone`でリポジトリを取得した後に`git checkout`でscarthgap向けのリソースに切り替えます。

https://zenn.dev/nbo/articles/6c4493f6124f8f

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/47dc7e63-ef48-9525-d928-10bef4bbb8e2.png)

https://github.com/NobuoTsukamoto/meta-tensorflow-lite

```bash
$ cd ~/scarthgap-work-2024_v1/poky
$ git clone https://github.com/NobuoTsukamoto/meta-tensorflow-lite.git
$ cd meta-tensorflow-lite/
$ git checkout -b scarthgap origin/scarthgap
```

### meta-onnxruntime

「meta-onnxruntime」は **ONNX形式のネットワークで推論を実行するためのLayer** です。`git clone`でリポジトリを取得した後に`git checkout`でscarthgap向けのリソースに切り替えます。

https://github.com/NobuoTsukamoto/meta-onnxruntime/tree/scarthgap

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/d7982d4b-fb0c-11c9-9a77-81f7566938cf.png)

```bash
$ cd ~/scarthgap-work-2024_v1/poky
$ git clone https://github.com/NobuoTsukamoto/meta-onnxruntime.git
$ cd meta-onnxruntime/
$ git checkout -b scarthgap origin/scarthgap
```

### meta-hailo <font color="red">【yocto 5.0非対応】</font>

<font color="red">**meta-hailoはYocto 5.x(scarthgap)をサポートしておらず、ビルドしたところ下記のエラーで停止してしまうことを確認しました。今回ビルドは対象から外します**</font>

https://community.hailo.ai/t/roadmap-for-hailo-8-support-meta-hailo-on-yocto-linux-5-0-scarthgap/2847

----

「meta-hailo」はRaspberry Pi 5 AI Kit向けのLayer群です。以下の機能を提供します。meta-hailoはSub-Layerである「meta-hailo-accelerator」「meta-hailo-libhailort」「meta-hailo-tappas」「meta-hailo-vpu」から構成されています。 **Raspberry Pi向けには「meta-hailo-accelerator」「meta-hailo-libhailort」「meta-hailo-tappas」** を利用します。

- HailoRT library
- HailoRT drivers
- Firmware for Hailo devices 
- pyHailoRT - HailoRT Python API (wraps the run-time library)

~~<font color="red">**なお、meta-hailoはscarthgap向けのブランチを持っていませんので、今回は最新となるYocto 4.0.23(kirkstone)向けのブランチを使います。**</font> `git clone`でリポジトリを取得した後に`git checkout`でkirkstone向けのリソースに切り替えます。~~

https://github.com/hailo-ai/meta-hailo

https://www.macnica.co.jp/en/business/semiconductor/articles/hailo/145447/

```bash
# Layerの入手は下記のコマンドでできるように思えます
$ cd ~/scarthgap-work-2024_v1/poky
$ git clone https://github.com/hailo-ai/meta-hailo.git
$ cd meta-hailo
$ git checkout -b kirkstone origin/kirkstone

######
### Layerがkirkstone版のため設定ファイルのCOMPATに加筆
######
$ vi ./meta-hailo-accelerator/conf/layer.conf 
### LAYERの対応バージョンを切り替える
# LAYERSERIES_COMPAT_meta-hailo-accelerator = "kirkstone"
LAYERSERIES_COMPAT_meta-hailo-accelerator = "scarthgap"

$ vi ./meta-hailo-libhailort/conf/layer.conf 
### LAYERの対応バージョンを切り替える
# LAYERSERIES_COMPAT_meta-hailo-libhailort = "kirkstone"
LAYERSERIES_COMPAT_meta-hailo-libhailort = "scarthgap"

$ vi ./meta-hailo-tappas/conf/layer.conf 
### LAYERの対応バージョンを切り替える
# LAYERSERIES_COMPAT_meta-hailo-tappas = "kirkstone"
LAYERSERIES_COMPAT_meta-hailo-tappas = "scarthgap"
```

<font color="red">**また、このビルドスクリプトはi.MX用でありRapsbery Pi 5に対応していないため、以下の手順で常にHailo-8向けバイナリを生成するように(Raspberry Pi 5の構成向けに)ビルドスクリプトを書き足してください。**</font>

#### meta-hailo-tappasをRaspberry Pi 5 (Hailo-8)向けにする

「meta-hailo」はi.MX向けのLayerらしく、Raspberry Pi 5でビルドするとHailo-15のバイナリが生成されてしまうようです。そのため、下記の記事を参考に **ソースコードが常にHailo-8向けにビルドされるようビルドスクリプトを修正** しました。

https://community.hailo.ai/t/yocto-kirkstone-meta-hailo-build-failed/2258/8

```bash
# bitbake時にtappas-appsをビルドするレシピに移動
$ cd ../meta-hailo/meta-hailo-tappas/recipes-gstreamer/tappas-apps

# tappas-appを変更する
$ vi tappas-apps_3.30.0.bb 
# ...
# i.MX8の場合のみhailo8に切り替える箇所を変更
python () {
#    if 'imx8' in d.getVar('MACHINE'):
        d.setVar('REQS_FILE', d.getVar('REQS_IMX8_FILE'))
        d.setVar('ARM_APPS_DIR', d.getVar('IMX8_DIR'))
#    else:
#        d.setVar('REQS_FILE', d.getVar('REQS_HAILO15_FILE'))
#        d.setVar('ARM_APPS_DIR', d.getVar('HAILO15_DIR'))
#        d.appendVar('DEPENDS', " libmedialib-api xtensor")
}
# ...
```

またビルド時に **生成物が予定外の箇所に生成されることにより `do_install` が失敗する問題** については下記の対策を行いました。

```bash
# birbake時にlibhailrtを構成するスクリプトを変更
$ cd ~/scarthgap-work-2024_v1/poky/aiot-build/
$ vi ../meta-hailo/meta-hailo-libhailort/recipes-hailo/libhailort/libhailort_4.19.0.bb

do_install:append() {
# ...
# ビルド生成物が格納されるパスが変わっているので修正
#  install -m 0644 ${WORKDIR}/build/hailort/libhailort/src/CMakeFiles/Export/lib/cmake/HailoRT/*.cmake ${HAILORT_EXPORT_DIR}
  install -m 0644 ${WORKDIR}/build/hailort/libhailort/src/CMakeFiles/Export/*/*.cmake ${HAILORT_EXPORT_DIR}
# ...

###
# 本箇所によるエラーメッセージ
# install: cannot stat '/home/shino/scarthgap-work-2024_v1/poky/aiot-build/tmp/work/cortexa76-poky-linux/libhailort/4.19.0/build/hailort/libhailort/src/CMakeFiles/Export/lib/cmake/HailoRT/*.cmake': No such file or directory
# 以下のディレクトリが生成されてしまっている
# -->> ~/scarthgap-work-2024_v1/poky/aiot-build/tmp/work/cortexa76-poky-linux/libhailort/4.19.0/build/hailort/libhailort/src/CMakeFiles/Export/2889dedff7f789699a09a5260145dc0f/
###
```

ビルド中の **do_fetchでWANINGが発生する** 箇所にも修正を入れておきます。

```bash
# 作業ディレクトリへ移動
$ cd ~/scarthgap-work-2024_v1/poky/aiot-build/

# git:// でアクセスしている箇所に ;protocol=https を追加する
## -->> WARNING対策
$ vi ../meta-hailo//meta-hailo-tappas/recipes-gstreamer/xtl/xtl_0.7.3.bb
# SRC_URI = "git://github.com/xtensor-stack/xtl.git;name=xtl"
SRC_URI = "git://github.com/xtensor-stack/xtl.git;name=xtl;protocol=https"
```

## 設定ファイルを更新してビルドする

### bitbake-layersでレイヤーを統合する

ここまでの手順で収集した **「meta-*」の各LayerをYoctoのビルド対象に追加** します。bitbake-layersコマンドで各ディレクトリを指定することにより「./conf/bblayers.conf」が更新されます。`bitbake-layers add-layer`を実行後「./conf/bblayers.conf」ファイルにLayerが追加されていることを確認できます。

```bash
####
# ビルドディレクトリと設定ファイルの生成
####
$ cd ~/scarthgap-work-2024_v1/poky
$ pwd
# /home/shino/scarthgap-work-2024_v1/poky
$ source oe-init-build-env aiot-build

# 直前のコマンドにより作業ディレクトリがビルド用に切り替わる
$ pwd
# /home/shino/scarthgap-work-2024_v1/poky/aiot-build
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/cbf1ffe5-47d2-5b8a-b57f-f9d2d835c387.png)

```bash
$ ls conf/
# bblayers.conf
# conf-notes.txt
# conf-summary.txt
# local.conf
# templateconf.cfg

####
# Layerを追加する
####
# ビルド対象にRaspberry Pi 5 GUI向けのレイヤーを追加する
$ bitbake-layers add-layer ../meta-raspberrypi/
$ bitbake-layers add-layer ../meta-openembedded/meta-oe/
$ bitbake-layers add-layer ../meta-openembedded/meta-python/
$ bitbake-layers add-layer ../meta-openembedded/meta-multimedia/
$ bitbake-layers add-layer ../meta-openembedded/meta-networking/
$ bitbake-layers add-layer ../meta-openembedded/meta-filesystems/

# Docker向けのLayer
$ bitbake-layers add-layer ../meta-virtualization/

# 推論向けのLayer
$ bitbake-layers add-layer ../meta-tensorflow-lite/
$ bitbake-layers add-layer ../meta-onnxruntime/

# AI向けのLayer 
### 今回のビルドには含めない
# $ bitbake-layers add-layer ../meta-tensorflow/

# Raspberry Pi 5 AI Kit向けのLayer (kirkstone版)
### 今回のビルドには含めない
# $ bitbake-layers add-layer ../meta-hailo/meta-hailo-accelerator/
# $ bitbake-layers add-layer ../meta-hailo/meta-hailo-libhailort/
# $ bitbake-layers add-layer ../meta-hailo/meta-hailo-tappas/
### 今回のビルドには含めない
# $ bitbake-layers add-layer ../meta-hailo/meta-hailo-vpu/


####
# Layerを確認する
####
$ grep /home/shino ./conf/bblayers.conf 
  /home/shino/scarthgap-work-2024_v1/poky/meta \
  /home/shino/scarthgap-work-2024_v1/poky/meta-poky \
  /home/shino/scarthgap-work-2024_v1/poky/meta-yocto-bsp \
  /home/shino/scarthgap-work-2024_v1/poky/meta-raspberrypi \
  /home/shino/scarthgap-work-2024_v1/poky/meta-openembedded/meta-oe \
  /home/shino/scarthgap-work-2024_v1/poky/meta-openembedded/meta-python \
  /home/shino/scarthgap-work-2024_v1/poky/meta-openembedded/meta-multimedia \
  /home/shino/scarthgap-work-2024_v1/poky/meta-openembedded/meta-networking \
  /home/shino/scarthgap-work-2024_v1/poky/meta-openembedded/meta-filesystems \
  /home/shino/scarthgap-work-2024_v1/poky/meta-virtualization \
  /home/shino/scarthgap-work-2024_v1/poky/meta-tensorflow-lite \
  /home/shino/scarthgap-work-2024_v1/poky/meta-onnxruntime \
```

### ライセンス "MINPACK" に対応する <font color="blue">【Workaround】</font>

bitbakeすると下記のエラーメッセージが発生しビルドに失敗してしまうことがわかりました。これはYocto 5.0のビルド環境が「MINPACK」のLICENSEファイルを含んでいないためと思われます。

https://spdx.org/licenses/

```bash
# ERROR: libeigen-3.4.0-r0 do_create_spdx: Cannot find any text for license MINPACK
# ERROR: Logfile of failure stored in: /home/shino/scarthgap-work-2024_v1/poky/aiot-build/tmp/work/cortexa76-poky-linux/libeigen/3.4.0/temp/log.do_create_spdx.474996
# ERROR: Task (/home/shino/scarthgap-work-2024_v1/poky/meta-openembedded/meta-oe/recipes-support/libeigen/libeigen_3.4.0.bb:do_create_spdx) failed with exit code '1'
```

そこで **YoctoのビルドシステムにMINIPACKのライセンスファイルを準備します。** MINPACKのライセンスファイルを `meta/files/common-licenses` 以下に `MINPACK` として保存します。ライセンスファイルはgitにあるものを利用しました。

https://qiita.com/rg125_suzuki/items/9158e017b2d529aeb17f

```bash
# ライセンスファイルの格納先ディレクトリへ移動する
$ cd ~/scarthgap-work-2024_v1/poky/
$ cd meta/files/common-licenses/

# curlでライセンスファイルを取得する
$ sudo apt install curl

# ライセンスファイルをライセンス名で保存する
$ curl https://baltig.cnr.it/ectoplasm/spece/-/raw/feature/IMAS_adaptation/minpack-LICENSE.txt -o MINPACK
```

### conf/local.confでビルドの設定をする

各機能のリポジトリのREADMEや各種記事を参考に、 **Linuxディストリビューションに組み込みたいアプリケーション名や、それらのオプションを「./conf/local.conf」に指定** します。


https://qiita.com/byuu/items/95086d07e317dfe64ee2

https://community.nxp.com/t5/i-MX-Processors/imx8mm-mini-adding-python-opencv-to-yocto/m-p/1233965?profile.language=ja

https://stackoverflow.com/questions/32964257/building-gstreamer-using-yocto

https://community.nxp.com/t5/i-MX-Processors/how-to-compile-gstreamer-in-yocto/m-p/856407?profile.language=ja

https://community.nxp.com/t5/i-MX-Processors/i-MX8MP-EVK-v4l2-ctl-v4l-utils-missing/m-p/1476820#M191684

https://mickey-happygolucky.hatenablog.com/entry/2023/02/23/070542

https://yoctobbq.lineo.co.jp/?q=node/130

https://zenn.dev/morising362/articles/9d30bc7f0268ca

https://mickey-happygolucky.hatenablog.com/entry/2024/12/22/164557

https://qiita.com/naohikowatanabe/items/fb7abb2db601013b8e7a

https://www.digi.com/support/knowledge-base/how-to-add-curl-to-an-embedded-connectcore-som

https://zenn.dev/nbo/articles/6c4493f6124f8f

https://lists.yoctoproject.org/g/yocto/message/57468

https://www.macnica.co.jp/en/business/semiconductor/articles/hailo/145447/

#### westonをLinuxディストリビューションへ組み込む方法

https://docs.yoctoproject.org/5.0.5/dev-manual/wayland.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/f6696bde-1100-5250-4b75-de63225e38f7.png)

#### rootのパスワードを設定する

https://stackoverflow.com/questions/32274163/how-to-set-root-password-on-yocto-poky-image

```bash
# パスワード文字列 "testtest" をMD5-base passwordに変換する
$ openssl passwd -1 testtest
$1$YtdVyrZC$RBCUL//XC5pwkqOMo3TIn0

# この文字列を conf/local.conf に設定する
$ vi conf/local.conf
# ...
INHERIT += "extrausers"
EXTRA_USERS_PARAMS = "usermod -p '\$1\$YtdVyrZC\$RBCUL//XC5pwkqOMo3TIn0' root;"
# ...

```


**以上をまとめると「./conf/local.conf」は以下のようになります。** 

```bash
$ vi ./conf/local.conf

# ...
BB_NUMBER_THREADS = "8"
PARALLEL_MAKE = "-j 8"
# ...

# ...
# MACHINEにはRaspberry Pi 5を指定する
MACHINE ??= "raspberrypi5"
####
# 以下の設定を追記する
####
UBOOT_EXTRA_CONFIGS = "LPDDR4_8GB"
# ...

# ...
DISTRO ?= "poky"
# ...

# ...
####
# 以下の設定を追記する
####
DISTRO_FEATURES:append = " wayland"
CORE_IMAGE_EXTRA_INSTALL += "wayland weston"

# rootのパスワードを設定する ("openssl passwd -1"で生成)
INHERIT += "extrausers"
EXTRA_USERS_PARAMS = "usermod -p '\$1\$YtdVyrZC\$RBCUL//XC5pwkqOMo3TIn0' root;"

# option for systemd
DISTRO_FEATURES:append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = "systemd-compat-units"
INIT_MANAGER ?= "systemd"
EXTRA_IMAGE_FEATURES += "ssh-server-openssh"
DISTRO_FEATURES:append = " virtualization"
IMAGE_INSTALL:append = " packagegroup-docker"

### meta-hailoのビルドエラーにより除外
# IMAGE_INSTALL:append = " hailo-firmware hailortcli hailo-pci libgsthailo libgsthailotools tappas-apps hailo-post-processes tappas-tracers"
### meta-tensorflowのビルドエラーにより除外
# IMAGE_INSTALL:append = " tensorflow"

IMAGE_INSTALL:append = " python3 python3-numpy python3-opencv opencv"
IMAGE_INSTALL:append = " python3-tensorflow-lite libtensorflow-lite"
IMAGE_INSTALL:append = " onnxruntime"

IMAGE_INSTALL:append = " curl"
IMAGE_INSTALL:append = " v4l-utils"
IMAGE_INSTALL:append = " sudo"

# build option
FORTRAN:forcevariable = ",fortran"
LICENSE_FLAGS_ACCEPTED = "synaptics-killswitch"

# ...

####
# 変更を加えて保存する
####
```

----

### bitbakeでLinuxディストリビューションをビルドする

**「bitbake」コマンドにGUI付きビルドである「core-image-weston」を指定して、GUI付きのLinuxディストリビューションをビルド**します。8000〜10000パッケージ程度のビルドが実行されます。しばらくお待ちください。

```bash
######
### Linuxディストリビューションをビルドする
$ bitbake core-image-weston
# ...
# NOTE: Executing Tasks
# WARNING: core-image-weston-1.0-r0 do_populate_lic_deploy: QA Issue: The license listed Broadcom-RPi was not in the licenses collected for recipe rpi-bootfiles [license-file-missing]
# NOTE: Tasks Summary: Attempted 8546 tasks of which 8520 didn't need to be rerun and all succeeded.
# Summary: There was 1 WARNING message.
```

#### ビルド中にリソースを使い切れているか確認する

ビルド時間の長いYoctoでは、十分にリソースを使い切れているかがビルド時間に直結します。そのため、Activity Monitor等を利用して、すべてのリソースが予定通りに使用できているのを確認しておきましょう。今回ビルド環境にCore i7-6700とRAM32GB搭載していますのでCPUの使用率が高ければ十分と言えるでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/59dc1e68-c024-c0f6-718d-8770532f2a4e.png)


### Linuxディストリビューションをインストールする

ビルドしたLinuxディストリビューションをRaspberry Pi 5起動用のmicro-SDカードへ書き込みます。書き込みは下記の手順で実施してください。

```bash
# イメージをmicro-SDカードへインストールする
$ ls ./tmp/deploy/images/raspberrypi5/*.wic.bz2
# ./tmp/deploy/images/raspberrypi5/core-image-weston-raspberrypi5.rootfs-20241231035454.wic.bz2
# ./tmp/deploy/images/raspberrypi5/core-image-weston-raspberrypi5.rootfs.wic.bz2
$ sudo umount /dev/sdX1
$ sudo umount /dev/sdX2
$ sudo bmaptool copy ./tmp/deploy/images/raspberrypi5/core-image-weston-raspberrypi5.rootfs-20241231035454.wic.bz2 /dev/sdX
####
# micro-SDカードをRaspberry Pi 5に挿入して起動する
####
```

## Linuxディストリビューションの動作を確認する

以下のスクリーンショットのように各機能の動作を確認することができます。

### Python3 / Tensorflow Lite / ONNX runtime の動作確認

起動画面は以下の通りです。Networkが機能しており、Python3上でTensorflow LiteとONNX runtimeを呼び出すことに成功しています。

![WIN_20241231_15_26_42_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/c35d50b0-a9a1-b915-91a1-71a14dae3ce0.jpeg)

### sudo / Docker / Networking の動作確認

Dockerdを起動して、`docker run hello-world`に成功することも確認できます。

![WIN_20241231_15_52_37_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/2f753509-1f36-0f4b-098f-187d18b05ee2.jpeg)

### Python3 / OpenCV の動作確認

https://www.klv.co.jp/corner/python-opencv-video-capture.html

`v4l2-ctl` コマンドによりWEBカメラのリストを確認し、Python3からOpenCVを呼び出し、WEBカメラの画像を撮影、`imshow` + `waitKey` により表示させることも可能です。

![WIN_20241231_19_45_29_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/ea07b6e1-fd25-836a-143c-85c111a4b7ee.jpeg)

## Linuxディストリビューション向けSDKを準備する

続いて、アプリケーション開発用のSDKを準備していきましょう。

### SDKを生成するためにlocal.confを修正する

`local.conf` に `TOOLCHAIN_TARGET_TASK` と `TOOLCHAIN_HOST_TASK` を指定してSDKに含まれるリソースを選択します。`TOOLCHAIN_TARGET_TASK` に指定するのはクロスプラットフォームビルドに必要となるターゲットに関するリソースであり、`TOOLCHAIN_HOST_TASK` に指定するのはビルドに必要なホスト(開発環境)が必要とするツールです。

https://stackoverflow.com/questions/60113300/toolchain-host-task-vs-toolchain-target-task

```bash
# 作業ディレクトリは前回記事と同様
$ pwd
# /home/shino/yocto-work-2024_v1/poky/aiot-build

# 設定ファイルを更新する
$ vi conf/local.conf 
# 以下の行を追加する
# ...
# for development
TOOLCHAIN_TARGET_TASK:append = " kernel-dev kernel-devsrc"
TOOLCHAIN_HOST_TASK:append = " nativesdk-openssl-dev nativesdk-bison nativesdk-flex nativesdk-cmake"
# ...
```

#### TOOLCHAIN_HOST_TASKに指定可能なパッケージ

`TOOLCHAIN_HOST_TASK` に指定できるパッケージは以下をご参照ください。

https://github.com/openembedded/openembedded-core/blob/master/meta/recipes-core/packagegroups/nativesdk-packagegroup-sdk-host.bb

**Bison**

https://ja.m.wikipedia.org/wiki/Bison

**Flex**

https://m.php.cn/ja/faq/489515.html

**CMake**

https://stackoverflow.com/questions/38049377/how-to-build-a-sdk-with-yocto-including-cmake

### LinuxディストリビューションとそのSDKをビルドする

ソースコードと設定ファイルの準備ができたら `bitbake` します。 `bitbake [target] -c populate_sdk` を実行することによりSDKを生成することができます。

```bash
# Linuxディストリビューションをビルドする
$ bitbake core-image-weston
# ...
# NOTE: Executing Tasks
# NOTE: Tasks Summary: Attempted 7688 tasks of which 7677 didn't need to be rerun and all succeeded.

####
# イメージをmicro-SDカードへインストールする
$ ls ./tmp/deploy/images/raspberrypi5/*.wic.bz2
# ./tmp/deploy/images/raspberrypi5/core-image-weston-raspberrypi5.rootfs-20241231035454.wic.bz2
# ./tmp/deploy/images/raspberrypi5/core-image-weston-raspberrypi5.rootfs.wic.bz2
$ sudo umount /dev/sdX1
$ sudo umount /dev/sdX2
$ sudo bmaptool copy ./tmp/deploy/images/raspberrypi5/core-image-weston-raspberrypi5.rootfs-20241231035454.wic.bz2 /dev/sdX
####

# 開発ツールと依存するヘッダー等をビルドする
$ bitbake core-image-weston -c populate_sdk
# ...https://note.com/yamblue/n/n1741975068c1
# NOTE: Executing Tasks
# NOTE: Tasks Summary: Attempted 7949 tasks of which 7899 didn't need to be rerun and all succeeded.

# 生成された開発ツールを確認する
$ ls ./tmp/deploy/sdk/*.sh
# ./tmp/deploy/sdk/poky-glibc-x86_64-core-image-weston-cortexa76-raspberrypi5-toolchain-5.0.5.sh
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/3f6efacf-1bac-021a-705a-1a3ea045e385.png)

### yoctoで生成したLinuxディストリビューションに対応するアプリケーション開発用のSDKをインストールする

yoctoで生成したLinuxディストリビューションに対応するSDKを作成できましたので、早速インストールしてみましょう。 **デフォルトのインストール先は `/opt` です。** インストールした後、Linuxディストリビューションに含まれるrootfsに移動し、 **カーネルモジュールのビルドに必要となる `make modules_prepare` をLinuxカーネルに対して実行** します。

```bash
# インストール先ディレクトリのパーミッションを変更
$ sudo chmod 0777 /opt

# 生成されたツールチェインを確認する
$ pwd
# /home/shino/scarthgap-work-2024_v1/poky/aiot-build
$ cd ./tmp/deploy/sdk/
$ pwd
# /home/shino/scarthgap-work-2024_v1/poky/aiot-build/tmp/deploy/sdk
$ ls *.sh
# poky-glibc-x86_64-core-image-weston-cortexa76-raspberrypi5-toolchain-5.0.5.sh

# ツールチェインをインストールする
$ ./poky-glibc-x86_64-core-image-weston-cortexa76-raspberrypi5-toolchain-5.0.5.sh 
# Poky (Yocto Project Reference Distro) SDK installer version 5.0.5
# =================================================================
# Enter target directory for SDK (default: /opt/poky/5.0.5): 
# You are about to install the SDK to "/opt/poky/5.0.5". Proceed [Y/n]?
# Extracting SDK...done
# Setting it up...done
# SDK has been successfully set up and is ready to be used.
# Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.
#  $ . /opt/poky/5.0.5/environment-setup-cortexa76-poky-linux

# インストールされたツールチェインを確認する
$ ls /opt/poky/5.0.5
# environment-setup-cortexa76-poky-linux
# sysroots
# site-config-cortexa76-poky-linux
# version-cortexa76-poky-linux

# ツールチェインを利用するために必要な環境変数を設定する
$ cd /opt/poky/5.0.5
$ . ./environment-setup-cortexa76-poky-linux 

# ツールチェインに含まれるカーネル開発に必要なオブジェクトをビルドする
$ cd ./sysroots/cortexa76-poky-linux/
$ pwd
# /opt/poky/5.0.5/sysroots/cortexa76-poky-linux
$ cd ./usr/src/kernel
$ make modules_prepare
#   SYNC    include/config/auto.conf.cmd
#   HOSTCC  scripts/basic/fixdep
#   HOSTCC  scripts/kconfig/conf.o
#   HOSTCC  scripts/kconfig/confdata.o
#   HOSTCC  scripts/kconfig/expr.o
#   LEX     scripts/kconfig/lexer.lex.c
#   YACC    scripts/kconfig/parser.tab.[ch]
#   HOSTCC  scripts/kconfig/lexer.lex.o
#   HOSTCC  scripts/kconfig/menu.o
#   HOSTCC  scripts/kconfig/parser.tab.o
#   HOSTCC  scripts/kconfig/preprocess.o
# ...
#   VDSOSYM include/generated/vdso-offsets.h
#   OBJCOPY arch/arm64/kernel/vdso/vdso.so
#   LDS     scripts/module.lds

$
```

---

## カーネルモジュールをビルドしてみる

最後に、作成したSDKを使ってカーネルモジュール `hello.ko` をビルドしてみましょう。Yocto向けのカーネルモジュールやアプリケーションのビルド、レシピの作成方法は、以下の **「meta-skelton」** が参考になります。

https://github.com/openembedded/openembedded-core/tree/master/meta-skeleton/recipes-kernel/hello-mod/files

以下の手順でx86_64ビルド環境上でターゲット(Raspberry Pi 5)向けのバイナリを生成することができます。

https://stackoverflow.com/questions/60923890/how-to-build-linux-kernel-module-using-yocto-sdk

```bash
# 作業用ディレクトリを作成する
$ mkdir ~/scarthgap-sample-mycode_v1
$ cd ~/scarthgap-sample-mycode_v1

# カーネルモジュールのサンプルソースコードを入手する
$ mkdir ./kernel_module_sample
$ cd ./kernel_module_sample
$ cp ~/scarthgap-work-2024_v1/poky/meta-skeleton/recipes-kernel/hello-mod/files/* ./

# ビルド用Makefileの内容を確認
$ cat Makefile
# obj-m := hello.o
# 
# SRC := $(shell pwd)
# 
# all:
# 	$(MAKE) -C $(KERNEL_SRC) M=$(SRC)
# 
# modules_install:
# 	$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
# 
# clean:
# 	rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
# 	rm -f Module.markers Module.symvers modules.order
# 	rm -rf .tmp_versions Modules.symvers

# 開発ツールの環境変数を設定する
$ . /opt/poky/5.0.5/environment-setup-cortexa76-poky-linux 

# 開発環境に設定されている環境変数を確認する
$ env
# PKG_CONFIG_PATH=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux/usr/lib/pkgconfig:/opt/poky/5.0.5/sysroots/cortexa76-poky-linux/usr/share/pkgconfig
# SDKTARGETSYSROOT=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux
# CPP=aarch64-poky-linux-gcc -E  -mcpu=cortex-a76+crypto -mbranch-protection=standard -fstack-protector-strong  -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux
# CXX=aarch64-poky-linux-g++  -mcpu=cortex-a76+crypto -mbranch-protection=standard -fstack-protector-strong  -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux
# KCFLAGS=--sysroot=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux
# OECORE_TARGET_SYSROOT=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux
# LD=aarch64-poky-linux-ld  --sysroot=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux
# PKG_CONFIG_SYSROOT_DIR=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux
# CC=aarch64-poky-linux-gcc  -mcpu=cortex-a76+crypto -mbranch-protection=standard -fstack-protector-strong  -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux
# CONFIGURE_FLAGS=--target=aarch64-poky-linux --host=aarch64-poky-linux --build=x86_64-linux --with-libtool-sysroot=/opt/poky/5.0.5/sysroots/cortexa76-poky-linux

# ビルドする
$ export KERNEL_SRC=$SDKTARGETSYSROOT/lib/modules/6.6.22-v8-16k/build 
$ make clean
# rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
# rm -f Module.markers Module.symvers modules.order
# rm -rf .tmp_versions Modules.symvers

$ make all
# make -C /opt/poky/5.0.5/sysroots/cortexa76-poky-linux/lib/modules/6.6.22-v8-16k/build M=/home/shino/scarthgap-sample-mycode_v1/kernel_module_sample
# make[1]: Entering directory '/opt/poky/5.0.5/sysroots/cortexa76-poky-linux/usr/lib/modules/6.6.22-v8-16k/build'
#   CC [M]  /home/shino/scarthgap-sample-mycode_v1/kernel_module_sample/hello.o
#   MODPOST /home/shino/scarthgap-sample-mycode_v1/kernel_module_sample/Module.symvers
#   CC [M]  /home/shino/scarthgap-sample-mycode_v1/kernel_module_sample/hello.mod.o
#   LD [M]  /home/shino/scarthgap-sample-mycode_v1/kernel_module_sample/hello.ko
# make[1]: Leaving directory '/opt/poky/5.0.5/sysroots/cortexa76-poky-linux/usr/lib/modules/6.6.22-v8-16k/build'

# ビルド成果物を確認する
$ ls .
# COPYING  hello.ko   hello.mod.c  hello.o   modules.order
# hello.c  hello.mod  hello.mod.o  Makefile  Module.symvers

# aarch64向けのバイナリを生成できている
$ file hello.ko
# hello.ko: ELF 64-bit LSB relocatable, 
# ARM aarch64, version 1 (SYSV), 
# BuildID[sha1]=f2319761c5dca0baa12bfbc7c60f3043d996fbb5, 
# not stripped

```

----

以上が、Yoctoを利用する基本手順となります。
是非開発にご活用ください！ありがとうございました！

----