Raspberry Pi 4とWSL2を使ってYocto Project入門

# はじめに

先日[Raspberry Pi 4でUbuntuデスクトップを動かして遊ぶ](https://qiita.com/y-tsutsu/items/b50d44bd70c25279d130)でラズパイを触ってみたのですが，今度はこのラズパイをYocto Projectを使って動かしてみました．
Yoctoをはじめて使ってみたのですが，いい入門になったと思うので内容をまとめます．

# Ycto Projectとは？

主には組込みおよびIoT向けのLinuxディストリビューションを作成するための仕組み・ツールが用意されています．柔軟にカスタマイズしながら組込みLinuxイメージをビルドすることができます．多くの組込みLinuxプロバイダで採用されているようです．
[Yocto Project - Wikipedia](https://en.wikipedia.org/wiki/Yocto_Project)

# やってみたこと

手もとにあったRaspberry Pi 4をYoctoでビルドしたイメージで起動してみました．

* Raspberry Pi 4をターゲットにしてビルド
* 簡単なレシピを用意してHello world！
* Wi-FiでSSH接続できるように設定
* Pythonを追加して開発環境の構築
* ツールチェーンを作成してクロスコンパイル環境構築

# 今回の開発環境

YoctoのビルドはWSL2のUbuntu 20.04 LTSで行いました．ターゲットは前述のとおりRaspberry Pi 4です．

* Windows 10 Pro（20H2）
* Ubuntu 20.04 LTS（WSL2）
* Yocto Project（3.2 Gatesgarth）
* Raspberry Pi 4（4GB）

# 前準備

まずはWSL2をインストールします．ディストリビューションは今回はUbuntu 20.04 LTSを使っています．
手順は例えばこちらを参考にしてください．
[https://docs.microsoft.com/ja-jp/windows/wsl/install-win10](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10)

環境が立ち上がったら，とりあえずパッケージの更新を行っておきます．

```console
$ sudo apt update && sudo apt upgrade -y
```

次に[Yocto Project Quick Start](https://www.yoctoproject.org/docs/2.4.2/yocto-project-qs/yocto-project-qs.html#the-linux-distro)を参考にして必要なパッケージのインストールを行います．

```console
$ sudo apt install -y gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat cpio python python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping libsdl1.2-dev xterm
```

# Raspberry Pi 4をターゲットにしてビルド

まずは[Poky](https://git.yoctoproject.org/cgit/cgit.cgi/poky/)（リファレンス・ディストリビューション）をGitでクローンします.
バージョンはこの時点で最新の`Gatesgarth(Yocto 3.2)`を指定しています．
[Releases - Yocto Project](https://wiki.yoctoproject.org/wiki/Releases)

```console
$ mkdir ~/yocto && cd ~/yocto
$ git clone git://git.yoctoproject.org/poky
$ cd poky
$ git checkout -b gatesgarth-24.0.1 refs/tags/gatesgarth-24.0.1
```

次にRaspberry Pi用のBSPレイヤーを追加します．
[OpenEmbedded Layer Index](https://layers.openembedded.org/layerindex/branch/master/layers/)に`meta-raspberrypi`というのがあるので，これをクローンします．ブランチはPokyに合わせて`gatesgarth`を指定しています．

```console
$ cd ~/yocto/poky
$ git clone git://git.yoctoproject.org/meta-raspberrypi
$ cd meta-raspberrypi
$ git checkout -b gatesgarth origin/gatesgarth
```

`meta-raspberrypi`のREADMEに書かれている手順を参考にします．

```
Dependencies
This layer depends on:
* URI: git://git.yoctoproject.org/poky
 - branch: master
 - revision: HEAD
* URI: git://git.openembedded.org/meta-openembedded
 - layers: meta-oe, meta-multimedia, meta-networking, meta-python
 - branch: master
 - revision: HEAD

Quick Start
1. source poky/oe-init-build-env rpi-build
2. Add this layer to bblayers.conf and the dependencies above
3. Set MACHINE in local.conf to one of the supported boards
4. bitbake core-image-base
5. Use bmaptool to copy the generated .wic.bz2 file to the SD card
6. Boot your RPI
```

まずは`oe-init-build-env`を読み込んで環境をセットアップします．実行すると`rpi-build`ディレクトリが作成されて移動しています．ビルドはこのディレクトリで行います．

```console
$ cd ~/yocto/poky
$ source oe-init-build-env rpi-build
```

次にこのレイヤーの追加設定を行います．`add-layer`すると`conf/bblayers.conf`に`meta-raspberrypi`が追加されます．

```console
$ bitbake-layers add-layer ../meta-raspberrypi/
$ cat conf/bblayers.conf
:
BBLAYERS ?= " \
  /home/user/yocto/poky/meta \
  /home/user/yocto/poky/meta-poky \
  /home/user/yocto/poky/meta-yocto-bsp \
  /home/user/yocto/poky/meta-raspberrypi \
  "
```

次にREADMEに書かれている依存レイヤーも同様に追加します．こちらもブランチは`gatesgarth`を指定します．また`add-layer`実行する順番によってエラーが出てしまうので，下記の順で追加を行ってください．

```console
$ cd ~/yocto/poky
$ git clone git://git.openembedded.org/meta-openembedded
$ cd meta-openembedded
$ git checkout -b gatesgarth origin/gatesgarth
$ cd ~/yocto/poky/rpi-build
$ 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/
$ cat conf/bblayers.conf
:
BBLAYERS ?= " \
  /home/user/yocto/poky/meta \
  /home/user/yocto/poky/meta-poky \
  /home/user/yocto/poky/meta-yocto-bsp \
  /home/user/yocto/poky/meta-raspberrypi \
  /home/user/yocto/poky/meta-openembedded/meta-oe \
  /home/user/yocto/poky/meta-openembedded/meta-python \
  /home/user/yocto/poky/meta-openembedded/meta-multimedia \
  /home/user/yocto/poky/meta-openembedded/meta-networking \
  "
```

次に`local.conf`の`MACHINE`を設定します．指定するマシン名は[こちら](https://layers.openembedded.org/layerindex/branch/master/layer/meta-raspberrypi/)のMachinesを参考にしてください．今回は下記のように設定しています．

```conf:~/yocto/poky/rpi-build/conf/local.conf
MACHINE ?= "raspberrypi4-64"
```

最後にWSL2を使った場合に下記のエラーがビルド時に出てしまいました．（VMwareにインストールしたUbuntu 18.04ではこのエラーは発生しませんでした．）[Stack Overflow](https://stackoverflow.com/questions/65274411/yocto-build-fail-with-exit-code-134)にあった対処で解決しました．

```console
ERROR: Task (/home/user/yocto/poky/meta/recipes-kernel/linux-libc-headers/linux-libc-headers_5.8.bb:do_install) failed with exit code '134'
```

```conf:~/yocto/poky/rpi-build/conf/local.conf
PSEUDO_IGNORE_PATHS_append = ",/run/"
```

ここまでで設定は完了です．`bitbake`コマンドでビルドを実行します．ビルドにはかなり時間がかかりますし，PCもフルで動きます．気長に待ちましょう．
参考に自分のノートPC（CPU：Core i7-8550U，メモリ：16.0 GB）では3～4時間ほどかかりました．またSSDは50GBほど使用します．

```console
$ cd ~/yocto/poky/rpi-build
$ bitbake core-image-base
```

またWSL2を使用している場合は下記の警告が表示されます．対処は[こちら](https://www.yoctoproject.org/docs/current/mega-manual/mega-manual.html#setting-up-to-use-wsl)の「6. Optimize your WSLv2 storage often」参照してください．

```
WARNING: You are running bitbake under WSLv2, this works properly but you should optimize your VHDX file eventually to avoid running out of storage space
```

ビルドが完了すると`rpi-build/tmp/deploy/images/raspberrypi4-64`にOSイメージができあがっています．
`bmaptool`コマンドを使って`core-image-base-raspberrypi4-64.wic.bz2`をSDカードに書き込みます．ただ今回使用しているWSL2環境ではSDカードのデバイス名をどのように指定するのかが分かりませんでした．

```console
$ cd ~/yocto/poky/rpi-build/tmp/deploy/images/raspberrypi4-64
$ sudo apt install -y bmap-tools
$ sudo bmaptool copy core-image-base-raspberrypi4-64.wic.bz2 /dev/sdX  # SDカードのデバイス名をどのように指定できるのか不明
```

そこで今回はwic.bz2を解凍してからWindows上でRaspberry Pi Imagerを使ってSDカードに書き込みました．

```console
$ cd ~/yocto/poky/rpi-build/tmp/deploy/images/raspberrypi4-64
$ cp core-image-base-raspberrypi4-64.wic.bz2 /tmp/.  # シンボリックリンクになっているので適当な場所にコピー
$ bunzip2 /tmp/core-image-base-raspberrypi4-64.wic.bz2
$ mv /tmp/core-image-base-raspberrypi4-64.wic /mnt/c/Users/user/Downloads/.  # Windows側の適当なディレクトリに移動
```

Operating SystemでUse customから`core-image-base-raspberrypi4-64.wic`を選択してSDカードに書き込みます．
他にもEtcherやDD for Windowsなどで書き込んでも問題ないと思います．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45310/12cff74c-6e16-943a-d98b-bdebf40bbcbb.png)
作成したSDカードをラズパイに挿して電源を入れるとOSが起動します．
コンソールへの出力が止まってEnterキーを押すと`log in:`と表示されるので`root`でログインします．パスワードはありません．
成功すれば最小限の環境ですがしっかりとターミナルで操作が可能です．

```console
raspberrypi4-64 log in: root
root@raspberrypi4-64:~# uname -mnr
raspberrypi4-64 5.4.72-v8 aarch64
root@raspberrypi4-64:~# cat /etc/issue
Poky (Yocto Project Reference Distro) 3.2.1 \n \l
```

# 簡単なレシピを作成してHello world！

次は自前の簡単なソースコードを書いて，コンパイルしてできた実行バイナリをインストールする手順をまとめます．
下記が参考になります．
[Creating a General Layer Using the bitbake-layers Script](https://www.yoctoproject.org/docs/2.4.2/dev-manual/dev-manual.html#creating-a-general-layer-using-the-bitbake-layers-script)

まずはレイヤーを作成します．下記のコマンドを実行すると`meta-hello`ディレクトリとその中に雛形が作成されます．

```console
$ cd ~/yocto/poky
$ bitbake-layers create-layer meta-hello
$ ls meta-hello/
COPYING.MIT  README  conf  recipes-example
```

続けて作成したレイヤーの追加設定を行います．

```console
$ cd ~/yocto/poky/rpi-build
$ bitbake-layers add-layer ../meta-hello/
$ cat conf/bblayers.conf
:
BBLAYERS ?= " \
  /home/user/yocto/poky/meta \
  /home/user/yocto/poky/meta-poky \
  /home/user/yocto/poky/meta-yocto-bsp \
  /home/user/yocto/poky/meta-raspberrypi \
  /home/user/yocto/poky/meta-openembedded/meta-oe \
  /home/user/yocto/poky/meta-openembedded/meta-python \
  /home/user/yocto/poky/meta-openembedded/meta-multimedia \
  /home/user/yocto/poky/meta-openembedded/meta-networking \
  /home/user/yocto/poky/meta-hello \
```

次にソースコードを用意します．下記のように`files`ディレクトリを作成しソースコードを配置します．

```console
$ cd ~/yocto/poky/meta-hello
$ mkdir -p recipes-hello/hello && cd recipes-hello/hello
$ mkdir files && cd files
$ vim hello.c
```

用意したのはC言語のHello worldです．

```c:hello.c
#include <stdio.h>

int main(int argc, char const *argv[])
{
    printf("Hello, world!\n");
    return 0;
}
```

次にレシピ（パッケージのビルドのために使用されるメタデータ）を作成します．

```console
$ cd ~/yocto/poky/meta-hello/recipes-hello/hello
$ vim hello_1.0.bb
```

レシピファイルの書き方はこちらが参考になります．
[Single .c File Package (Hello World!)](https://www.yoctoproject.org/docs/2.4.2/dev-manual/dev-manual.html#new-recipe-single-c-file-package-hello-world)
ただし，このままではビルドに失敗するので`TARGET_CC_ARCH += "${LDFLAGS}"`を追加します．
[Default Linker Hash Style Changed](https://www.yoctoproject.org/docs/2.4.2/ref-manual/ref-manual.html#migration-2.2-default-linker-hash-style-changed)
また`LIC_FILES_CHKSUM`の`md5`が分からない場合は空白にしておくと，ビルド時に正しい値がエラーで表示されます．

```text:hello_1.0.bb
SUMMARY = "Simple helloworld application"
SECTION = "hello"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

TARGET_CC_ARCH += "${LDFLAGS}"

SRC_URI = "file://hello.c"

S = "${WORKDIR}"

do_compile() {
    ${CC} hello.c -o hello
}

do_install() {
    install -d ${D}${bindir}
    install -m 0755 hello ${D}${bindir}
}
```

最終的に次のようなディレクトリ・ファイル構成になります．

```text
meta-hello/
├── COPYING.MIT
├── README
├── conf
│   └── layer.conf
├── recipes-example
│   └── example
│       └── example_0.1.bb
└── recipes-hello
    └── hello
        ├── files
        │   └── hello.c
        └── hello_1.0.bb
```

最後に`local.conf`の`IMAGE_INSTALL_append`でイメージの追加を指定します．

```conf:~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " hello"  # 先頭の空白文字が必要なので注意
```

ここまで準備ができたらビルドを行います．

```console
$ cd ~/yocto/poky/rpi-build/
$ bitbake core-image-base
```

できあがったOSイメージをSDカードに書き込んでラズパイで起動します．ログインして`hello`コマンドが実行できることを確認します．うまくいくと`Hello, world!`が表示されます．

```console
raspberrypi4-64 log in: root
root@raspberrypi4-64:~# hello
Hello, world!
```

# Wi-FiでSSH接続できるように設定

次はWi-Fi経由でSSH接続できるように設定します．
ここまでの環境で，`ip`コマンドで確認すると`wlan0`は認識されているようです．

```console
root@raspberrypi4-64:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq qlen 1000
    link/ether dc:a6:32:b8:2b:4a brd ff:ff:ff:ff:ff:ff
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP8000> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether dc:a6:32:b8:2b:4b brd ff:ff:ff:ff:ff:ff
```

Wi-Fi接続を行うにはConnManを使用するのが簡単そうです．local.confでイメージの追加設定を行います．
またSSH接続を行うためにOpenSSHの追加を行います．[こちら](https://blog.web.nifty.com/engineer/1040)を参考にして`IMAGE_FEATURES`に指定するとよさそうです．

```conf:~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " connman connman-client"
IMAGE_FEATURES_append = " ssh-server-openssh"
```

ここまでで`bitbake core-image-base`してOSイメージをビルドして，SDカードからラズパイを起動します．
`connmanctl`コマンドを使って次の手順でWi-Fi接続設定を行います．

```console
root@raspberrypi4-64:~# connmanctl
connmanctl> enable wifi
connmanctl> scan wifi
connmanctl> services
    Buffalo-A-0F20       wifi_dca632b82b4b_42756666616c6f2d412d30463230_managed_psk
    Buffalo-G-0F20       wifi_dca632b82b4b_42756666616c6f2d472d30463230_managed_psk
    WARPSTAR-D56FD6      wifi_dca632b82b4b_57415250535441522d443536464436_managed_psk
connmanctl> agent on
connmanctl> connect wifi_dca632b82b4b_42756666616c6f2d412d30463230_managed_psk
Passphrase?
connmanctl> exit
```

パスフレーズの入力まで完了したら`connmanctl`を終了し，再度`ip`コマンドで確認すると`wlan0`にIPアドレスが割り振られています．
このIPアドレスにSSH接続を試すとrootでログインができるはずです．

```console
$ ssh root@192.168.1.8  # ラズパイのwlan0に割当たっているIPアドレス
Last login: Sun Jan 10 02:06:14 2021 from 192.168.1.7
root@raspberrypi4-64:~#
```

SSH接続とは直接関係ないですが，手もとの開発環境でSFTPが使えると便利だったので追加しています．
ついでにrootのパスワード設定とpiユーザの新規作成も行っておきます．あわせて`sudo`コマンドも追加します．
またOpenSSHの追加で調べているとsystemdを有効にする設定をよく見かけたのでこれも入れておきます．

```conf:~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " openssh-sftp-server sudo"
IMAGE_FEATURES_append = " ssh-server-openssh"

# user settings
INHERIT_append = " extrausers"
EXTRA_USERS_PARAMS = "useradd -P raspberry pi;usermod -P raspberry root;"

# systemd settings
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""
IMX_DEFAULT_DISTRO_FEATURES_append = " systemd"
```

ここまででビルドして，ラズパイで起動してSSH接続を確認します．（今回のビルドはまた時間がそこそこかかります．）
rootの他にpiユーザでもSSHでログインできます．パスワードは新規に設定したものを使用します．（この例だと`raspberry`）

piユーザでsudoを使えるようにするにはrootから`visudo`コマンドで設定します．

```config:/etc/sudoers
root ALL=(ALL) ALL
pi   ALL=(ALL) ALL  # ここを追記
```

# Pythonを追加して開発環境の構築

開発環境としてPythonを追加します．ラズパイを使っているので`rpi-gpio`を追加してGPIOの制御を簡単に行ってみます．また手元にLEDなどがなかったので，`raspi-gpio`というGPIOを制御するコマンドを使って確認をします．

```conf:~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " python3 python3-pip rpi-gpio raspi-gpio"
```

OSイメージをビルドしてラズパイで起動します．rootユーザで確認をしています．
Pythonとpipが使用できるか確認してみます．下記のように出力されて`rpi-gpio`が追加されていることも確認できます．

```console
# python3 --version
Python 3.8.5
# python3 -m pip list
Package    Version
---------- -------
pip        20.0.2
RPi.GPIO   0.7.0
setuptools 49.6.0
```

`raspi-gpio`コマンドが使えることも確認しておきます．helpで簡単な使い方が確認できると思います．
GPIO1番ピンはデフォルトだと入力でプルアップになっているようです．

```console
# raspi-gpio help
# raspi-gpio get 1
GPIO 1: level=1 fsel=0 func=INPUT pull=UP
```

PythonでGPIOを制御する簡単なサンプルコードを書きます．GPIO1番ピンを出力設定にして，1秒ごとにON/OFFを切り替えます．

```py:gpio.py
import time
import RPi.GPIO as GPIO

def main():
    pin_num = 1
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(pin_num, GPIO.OUT)
    for i in range(10):
        GPIO.output(pin_num, i % 2)
        print(f'GPIO {"ON" if i % 2 else "OFF"}')
        time.sleep(1)
    GPIO.cleanup(pin_num)

if __name__ == '__main__':
    main()
```

上記のPythonコードを実行しながら`raspi-gpio`を繰り返し実行してGPIO1番ピンを確認すると，funcが出力に切り替わってlevelが0/1と切り替わっている様子が確認できます．

```console
# python3 gpio.py  # 実行中に下記を別セッションで確認
# raspi-gpio get 1
GPIO 1: level=0 fsel=1 func=OUTPUT pull=NONE
# raspi-gpio get 1
GPIO 1: level=1 fsel=1 func=OUTPUT pull=NONE
# raspi-gpio get 1
GPIO 1: level=0 fsel=1 func=OUTPUT pull=NONE
# raspi-gpio get 1
GPIO 1: level=1 fsel=1 func=OUTPUT pull=NONE
```

## GPIOをデバイスファイルから制御する方法

raspi-gpioを使わずにGPIOをデバイスファイルから制御する方法についても簡単にまとめておきます．
下記の手順で確認するとGPIO1番ピンがデフォルトでは入力になっているのが分かります．この方法でもPythonのサンプルコードを実行して出力に切り替わってON/OFFしている様子が確認できます．

```console
# cd /sys/class/gpio
# ls
export       gpiochip0    gpiochip504  unexport
# echo 1 > export
# ls
export       gpio1        gpiochip0    gpiochip504  unexport
# cd gpio1
# ls
active_low  device      direction   edge        power       subsystem   uevent      value
# cat active_low direction value
0
in
1
```

# ツールチェーンを作成してクロスコンパイル環境構築

最後にツールチェーンをビルドして，ローカルのPCにクロスコンパイル環境を構築します．
今回はC++のコードをビルドして動かしたのですが，実行すると`libstdc++.so.6`が見つからないというエラーが出ました．C++標準ライブラリがデフォルトでは入っていなさそうなので，追加の設定を行います．

```conf:~/yocto/poky/rpi-build/conf/local.conf
IMAGE_INSTALL_append = " libstdc++"
TOOLCHAIN_TARGET_TASK_append = " libstdc++-staticdev"
```

ここまでの内容をまとめると，最終的にlocal.confは次の内容になっています．

```conf:~/yocto/poky/rpi-build/conf/local.conf
MACHINE ?= "raspberrypi4-64"

# for WSL2
PSEUDO_IGNORE_PATHS_append = ",/run/"

# image
IMAGE_INSTALL_append = " hello connman connman-client openssh-sftp-server sudo python3 python3-pip rpi-gpio raspi-gpio libstdc++"
IMAGE_FEATURES_append = " ssh-server-openssh"

# user settings
INHERIT_append = " extrausers"
EXTRA_USERS_PARAMS = "useradd -P raspberry pi;usermod -P raspberry root;"

# systemd settings
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""
IMX_DEFAULT_DISTRO_FEATURES_append = " systemd"

# for c++
TOOLCHAIN_TARGET_TASK_append = " libstdc++-staticdev"
```

local.confを書き終えたらOSイメージとツールチェーンのビルドを行います．ツールチェーンのビルドにはまた時間がかかりますのでゆっくりと待ちましょう．またSSDもこれまでの手順で80GBほど使用しますので注意してください．

```console
$ cd ~/yocto/poky/rpi-build
$ bitbake core-image-base
$ bitbake core-image-base -c populate_sdk  # ツールチェーンのビルド
```

ビルドが完了すると`rpi-build/tmp/deploy/sdk`にツールチェーンができあがっています．この中の.shファイルを実行するとインストールを行うことができます．インストール先はデフォルトでは`/opt/poky/3.2.1`になっています．
`environment-setup-cortexa72-poky-linux`を読み込むとクロスコンパイル環境を使うことができます．

```console
$ cd ~/yocto/poky/rpi-build/tmp/deploy/sdk
$ sudo ./poky-glibc-x86_64-core-image-base-cortexa72-raspberrypi4-64-toolchain-3.2.1.sh
$ source /opt/poky/3.2.1/environment-setup-cortexa72-poky-linux
```

今回はC++のHello world！をCMakeを使ってビルドしてラズパイで動かしてみます．

```console
$ mkdir ~/hello && cd ~/hello
$ vim hello.cpp
$ vim CMakeLists.txt
$ mkdir build && cd build
$ cmake ..
$ make
```

今回使用した`hello.cpp`と`CMakeLists.txt`は次の内容です．

```cpp:hello.cpp
#include <iostream>

int main(int argc, char const *argv[])
{
    std::cout << "Hello, world!" << std::endl;
    return 0;
}
```

```cmake:CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(hello VERSION 0.1.0)

set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "limited configs" FORCE)

add_executable(hello
    hello.cpp
)

target_compile_features(hello
    PRIVATE cxx_std_17
)
```

ビルドしてできあがった実行バイナリを`readelf`コマンドで確認してみます．Machineが`AArch64`になっており，クロスコンパイルができていることが分かります．（今回ビルドを実施したPCは`x86_64`）

```console
$ readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           AArch64
  Version:                           0x1
  :
$ uname -m
x86_64
```

実行バイナリを`scp`コマンドでラズパイにコピーして動かすと，`Hello, world!`が表示されます．

```console:ローカルPC
$ scp ./hello root@192.168.1.8:/home/root/.
```

```console:RaspberryPi
# ~/hello
Hello, world!
```

# おわりに

今回はRaspberry Pi 4をターゲットにして，Yocto Projectを使ってLinuxをビルドし実際に動かしました．基本的な手順についてある程度は確認することができたと思います．Yoctoは日本語の情報が少ないのと，とにかくビルドに時間がかかってしまうため，初心者にはとっつきにくいところがあると感じました．この記事は，はじめてYoctoを触ってみる人にとって，ちょうどいいチュートリアルになると思います．Yoctoをはじめて触ってみる人たちの参考にしてもらえるとありがたいです．

## 参考にした書籍

最後に参考にした書籍の紹介です．とっかかりは[Yocto Project入門](https://techbookfest.org/product/6590025001074688)を参考にさせてもらいました．Yoctoをはじめて触ったので大変助かりました．今回まとめている内容も，特に前半はこちらの書籍の内容を参考にして自分の開発環境に合わせて動かし，また追加で調べながらまとめていきました．