Raspberry Pi3 with Yocto Project：環境構築

#本記事の目的
[Yocto Project](https://www.yoctoproject.org/)を用いて、[Raspberry Pi3](https://www.raspberrypi.org/products/raspberry-pi-3-model-b/)の開発環境を構築します。
最終的には、容易にアプリのクロス開発ができるように、SDK(ツールチェインやライブラリ)を作成します。

#対象者
・Yocto Projectに興味がある方(※)
・Raspberry Pi3のクロス開発環境を構築したい方
・ビルド作業を半自動化したい方
※：レシピ(後述)の書き方やレイヤー(後述)の追加方法などは別記事でまとめます。

#Yocto Projectとは
Yocto Project(以下、Yocto)は、カスタムLinuxディストリビューションを作成するためのビルドツールです。
Yoctoを利用すれば、コマンド一つで以下の項目を一度にビルドできます。
　・[Bootloader](http://e-words.jp/w/%E3%83%96%E3%83%BC%E3%83%88%E3%83%AD%E3%83%BC%E3%83%80.html)
　・[Device Tree Blob](http://qiita.com/koara-local/items/ed99a7b96a0ca252fc4e)
　・[Linux Kernel image](http://itpro.nikkeibp.co.jp/article/Keyword/20080215/293930/?rt=nocnt)
　・[toolchain](https://ja.wikipedia.org/wiki/GNU%E3%83%84%E3%83%BC%E3%83%AB%E3%83%81%E3%82%A7%E3%83%BC%E3%83%B3)
　・[rootfs](http://www.wdic.org/w/TECH/rootfs%20(Linux))
　・[Application](http://e-words.jp/w/%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%BD%E3%83%95%E3%83%88.html)
　・その他多数

このビルド機能を支えているのは、Bitbake(ビルドシステム)およびレシピ（ビルドに必要なメタ情報）です。
レシピにはソースコードの取得処理が含まれているので、
適切なレシピがあれば自作ソースコードがなくてもビルド処理が可能です(※1)。
Yoctoでは特定機能で集約したレシピをレイヤーと表現し、レイヤーはgitなどで公開されています。
日曜プログラマであれば、レイヤー(レシピ)を流用して、簡単にビルドを進められます(※2)。
※1：ローカルのソースファイルを使用することも当然できます。
※2：当然ですが、企業の人はライセンスを確認する必要があります。殆どが[MIT](https://ja.wikipedia.org/wiki/MIT_License)ですが。

Yoctoの良さは、長期的な運営計画や多くの支援団体の存在により、
数多くの便利なツールがリリース及びメンテナンスされ続けている点にあります。
ビルドツールの使い方を覚えるためにかかるコストを考えれば、
数年以上の継続使用が見込めるYoctoは、組込み開発者が一度ぐらい触っても損がないツールと言えます。
それなりに学習コストが高いですが、その他のツールに比べれば、リファレンスが充実していますよ。

#使用機器
　・Mac(OS X El Capitan 10.11.4)
　・[VirtualBox(5.0.16)](https://www.virtualbox.org/)
　・[Ubuntu16.04(64bit、isoファイル)](https://www.ubuntulinux.jp/)
　・[Raspberry Pi3 Model B](https://www.raspberrypi.org/)
　・microSD(8GB以上、Class10を推奨)

#仮想環境(Ubuntu)の準備
仮想環境は[「Raspberry Pi2　Linuxカーネルのクロスコンパイル方法」](http://qiita.com/Mogura1215/items/f4cf7988281fd807951c)を参考に準備してください。
ここで一点注意ですが、Yoctoはソースコード一式をダウンロードして、ビルドを開始するため、
一回目のビルドは、20~50GBの容量を使用します。
二回目のビルドは、過去のソースやキャッシュを流用するので、容量をそこまで使いません。
念のため、仮想環境のUbuntuの容量は100GB以上を確保した方が良いでしょう。

#Yocto Projectのインストール
以降の作業では、仮想環境のUbuntu上で操作を行います。
まず、Yoctoを動作させるのに必要なパッケージを取得します。
必要なパッケージは[公式リファレンス](http://www.yoctoproject.org/docs/2.1/yocto-project-qs/yocto-project-qs.html)に記述されています。不足があれば、リファレンスを参考に追加します。

```
$ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib \
  build-essential chrpath socat libsdl1.2-dev xterm
$ sudo apt-get update  　　# パッケージリストの更新
$ sudo apt-get upgrade 　　# インストールパッケージの更新
```

次に、Yoctoをインストールします。
今回使用するバージョンは、Yocto2.1(krogoth)とします。

```
$ cd ~/Desktop 　　　　　　　　　　　　　　　　　#日本語環境の場合、"~/デスクトップ"
$ git clone git://git.yoctoproject.org/poky -b krogoth
$ cd poky 　　　　　　　　　　　　　　　　　　　　#poky(yocto)のディレクトリに移動
```

ディレクトリ構成は、画像の通りです。
metaプレフィックスが付いているディレクトリはレイヤーで、その中にはレシピが入っています。
bitbakeディレクトリはビルドシステム(スクリプト)が格納されており、python2.7で記述されています。
![スクリーンショット 2016-06-20 21.46.22.png](https://qiita-image-store.s3.amazonaws.com/0/99011/13387342-f2a9-bae0-f11a-c5c3d84bb10f.png)

#Raspberry Pi3関連レイヤーの取得
デフォルトのレイヤーには、Raspberry Pi向けのレシピは含まれていません。
そのため、関連レイヤーを取得します。この時、Yoctoのバージョンに一致したレイヤーを取得しましょう。

```
$ cd ~/Desktop/poky 　　　　　　　　　　　　　　#日本語環境の場合、"~/デスクトップ/poky"
$ git clone -b krogoth https://github.com/meta-qt5/meta-qt5.git
$ git clone -b krogoth git://git.openembedded.org/meta-openembedded
$ git clone -b krogoth git://github.com/jumpnow/meta-rpi
$ git clone -b master git://git.yoctoproject.org/meta-raspberrypi # krogothブランチがないためmasterで代用。
```

#ビルド環境の設定
Yoctoには、ビルド環境セットアップスクリプトが含まれています。
このスクリプトを実行する事により、環境変数が設定され、Raspberry Pi用ビルドディレクトリが生成された後、
そのディレクトリに自動で移動します。まず、そのスクリプトを実行します。

```
$ cd ~/Desktop/poky 　　　　　　　　　 #日本語環境の場合、"~/デスクトップ/poky"
$ source oe-init-build-env build_rpi  #build_rpiは、任意のディレクトリ名
```

カレントディレクトリがbuild_rpに自動的に移動した事を確認できたら、スクリプトは成功です。
次に、使用ボード(Raspberry Pi)とレイヤーを明示するため、2個のコンフィグファイルを編集します。
今回はmeta-rpiレイヤーにコンフィグファイルのサンプルが含まれていますので、それを利用します。

```
# カレントディレクトリは、build_rpi
$ cp ../meta-rpi/conf/local.conf-sample conf/local.conf
$ cp ../meta-rpi/conf/bblayers.conf-sample conf/bblayers.conf
```

local.conf内のMACHINE変数に、"raspberrypi2"が代入されていますが、
"raspberrypi3"との違いはWifi Driverの有無のようです。
今回は、MACHINE変数を変更せず、そのままにしておきます。

bblayer.confは、そのまま使用するとパスに関するエラーが発生するので、
以下のように修正する必要があります。
注意："~/"を用いたホームディレクトリの簡略表記は、使用できません。

```conf/bblayers.conf
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

BBLAYERS ?= " \
    ${HOME}/Desktop/poky/meta \
    ${HOME}/Desktop/poky/meta-poky \
    ${HOME}/Desktop/poky/meta-openembedded/meta-oe \
    ${HOME}/Desktop/poky/meta-openembedded/meta-multimedia \
    ${HOME}/Desktop/poky/meta-openembedded/meta-networking \
    ${HOME}/Desktop/poky/meta-openembedded/meta-python \
    ${HOME}/Desktop/poky/meta-qt5 \
    ${HOME}/Desktop/poky/meta-raspberrypi \
    ${HOME}/Desktop/poky/meta-rpi \
  "
```

最後に、Ubuntu16.04ならではの設定を行います(古めの環境では不要な設定です)。
今回使用しているレイヤーは、Ubuntu16.04での検証が完了していないため、
Sanityチェックエラーが発生します(後述)。
そこで、暫定の処置として、Sanityチェックが発生しないようにします。
具体的な方法は、Sanityチェックに関する空の設定ファルを作成する事です。

```
$ touch conf/sanity.conf # デフォルトのsanity.confは、metaレイヤーに存在する。
                         # ビルド用のディレクトリに同名ファイル(sanity.conf)を配置する事で、設定が上書きされる。
```
```sanity_error_message.
WARNING: Host distribution "Ubuntu-16.04" has not been validated with this version of the build system; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.
ERROR:  OE-core's config sanity checker detected a potential misconfiguration.
    Either fix the cause of this error or at your own risk disable the checker (see sanity.conf).
    Following is the list of potential problems / advisories:

    Error, the PACKAGE_ARCHS variable (all any noarch armv5hf-vfp armv5thf-vfp armv5ehf-vfp armv5tehf-vfp armv6hf-vfp armv6thf-vfp armv7ahf-vfp armv7at2hf-vfp armv7vehf-vfp armv7vet2hf-vfp armv7vehf-neon armv7vet2hf-neon armv7vehf-neon-vfpv4 armv7vet2hf-neon-vfpv4 cortexa7hf-vfp cortexa7hf-neon cortexa7hf-neon-vfpv4 cortexa7t2hf-vfp cortexa7t2hf-neon cortexa7t2hf-neon-vfpv4 raspberrypi2) for DEFAULTTUNE (cortexa7thf-neon-vfpv4) does not contain TUNE_PKGARCH (cortexa7hf-neonvfpv4).

Summary: There was 1 WARNING message shown.
Summary: There was 1 ERROR message shown, returning a non-zero exit code.
```


# ビルド(SDKの作成)
ここまでくれば、残りはbitbakeコマンドを叩くだけです(※)。
数時間はかかるので、暇をつぶしましょう。私はこのビルド時間で本記事を書きました。
※今回の方法では、ビルド時にエラーが発生する可能性があります。対処法は後述。

```
$ bitbake console-image -c  populate_sdk_ext
```

上記のコマンドを実行後、レシピの解析が始まり、
各パッケージの依存関係を考慮した順番で、ビルドタスクが実行されます。
主なビルドタスクを以下の表に示します。
詳しく知りたい方は[公式リファレンス](http://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html)を"do_"プレフィックスで検索しましょう。

| ビルドタスク  | 役割 |
|:----------------|:---------------------------------|
|do_fetch  | レシピに記載されたURL(SRC_URI)を元に、ソースコードを取得する。  |
|do_unpack | ソースコード(tarなど)を展開する。  |
|do_patch | ソースコードにパッチを適用する。  |
|do_configure   | [GNU Automake](http://www.02.246.ne.jp/~torutk/cxx/automake/automake.html)によって、Makefileを作成する。  |
|do_compile  | ソースコードをコンパイルする。  |
|do_install   | 指定のディレクトリに、コンパイルによる生成物をインストールする。  |
|do_populate_sysroot   | sysrootを作成する。  |
| do_package  | パッケージを作成する。  |

#ビルドエラー(do_fetchエラー)
git://github.com/raspberrypi/firmware.gitからファイルが取得できないエラーが発生します。
このエラーは、gitのバッファ設定に起因するものです。回線が貧弱な場合発生します。

```error_message.
WARNING: bcm2835-bootfiles-20160512-r3 do_fetch: Failed to fetch URL git://github.com/raspberrypi/firmware.git;protocol=git;branch=master, attempting MIRRORS if available
ERROR: bcm2835-bootfiles-20160512-r3 do_fetch: Fetcher failure: Fetch command failed with exit code 128, output:
Cloning into bare repository '/home/username/Desktop/poky/build_rp/downloads/git2/github.com.raspberrypi.firmware.git'...
fatal: The remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed

ERROR: bcm2835-bootfiles-20160512-r3 do_fetch: Function failed: Fetcher failure for URL: 'git://github.com/raspberrypi/firmware.git;protocol=git;branch=master'. Unable to fetch URL from any source.
ERROR: Logfile of failure stored in: /home/username/Desktop/poky/build_rp/tmp/work/raspberrypi-poky-linux-gnueabi/bcm2835-bootfiles/20160512-r3/temp/log.do_fetch.2117
ERROR: Task /home/username/Desktop/poky/meta-raspberrypi/recipes-bsp/bootfiles/bcm2835-bootfiles.bb:do_fetch (/home/username/Desktop/poky/meta-raspberrypi/recipes-bsp/bootfiles/bcm2835-bootfiles.bb:do_fetch) failed with exit code '1'
NOTE: Tasks Summary: Attempted 1376 tasks of which 1375 didn't need to be rerun and 1 failed.

Summary: 1 task failed:
  /home/username/Desktop/poky/meta-raspberrypi/recipes-bsp/bootfiles/bcm2835-bootfiles.bb:do_fetch
Summary: There was 1 WARNING message shown.
Summary: There were 2 ERROR messages shown, returning a non-zero exit code.
```

[今回のエラー(fatal: The remote end hung up unexpectedly)は、
対処法がstackoverflowにありました。](http://stackoverflow.com/questions/15240815/git-fatal-the-remote-end-hung-up-unexpectedly)
gitのコンフィグ設定を変更して、大きめのバッファを扱えるようにすれば良いそうです。

```
$ cd ~/Desktop/poky/build_rpi/downloads/git2
$ git config http.postBuffer 54288000
$ cd ~/Desktop/poky/build_rpi/
$ bitbake console-image -c  populate_sdk_ext  #再ビルド
```


#生成物の格納場所
build_rpiディレクトリ以下のtmp/deployに生成物が格納されます。
以下に、deployのディレクトリ構造をtree構造で示し、ディレクトリ毎の格納物を表に示します。

```~/Desktop/poky/build_rpi/tmp/deploy
~/Desktop/poky/build_rpi/tmp/deploy
├── images
│   └── raspberrypi2
│       └── bcm2835-bootfiles
├── ipk
│   ├── all
│   ├── buildtools-dummy-nativesdk
│   ├── cortexa7hf-neon-vfpv4
│   ├── raspberrypi2
│   └── x86_64-nativesdk
├── licenses
│   ├── acl
│   ├── acl-native
│   ├── alsa-lib
│   ├── alsa-lib-native
│   ├── alsa-state
│   ├── alsa-utils
│   ├── attr
│   ├── attr-native
│   ├── autoconf-native
│   (省略)
│   ├── x264
│   ├── xz
│   ├── xz-native
│   ├── yasm-native
│   ├── zip
│   ├── zlib
│   └── zlib-native
└── sdk
```

| ディレクトリ名 | 格納物      |
|------------------|---------------------------------|
| images  |Kernel Image、DTB、rootfs、Bootloader|
| ipk  |  パッケージ(設定変更でrpm、dpkgも生成可能) |
| licenses  |  各パッケージに対するライセンス条文 |
| sdk  |   SDKインストーラ|

#SDKインストールおよびビルド環境設定
SDKを任意のディレクトリ以下に配置すれば、
Raspberry Pi3向けのクロス開発環境は作成完了になります。
このSDKインストール作業には、`~/Desktop/poky/tmp/deploy/sdk`内のスクリプトを使用します。

```
$ cd ~/Desktop/poky/tmp/deploy/sdk
$ bash poky-glibc-x86_64-core-image-minimal-cortexa7hf-neon-vfpv4-toolchain-ext-2.1.1.sh 
Poky (Yocto Project Reference Distro) Extensible SDK installer version 2.1.1
============================================================================
Enter target directory for SDK (default: ~/poky_sdk): 
You are about to install the SDK to "/home/username/poky_sdk". Proceed[Y/n]? Y
Extracting SDK...........................done
Setting it up...
Extracting buildtools...
Preparing build system...
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.
  $ . /home/username/poky_sdk/environment-setup-cortexa7hf-neon-vfpv4-poky-linux-gnueabi
$
```

上記が正常なインストール終了画面です。
以下に、SDKインストールディレクトリをtree構造で示します。
内容はpokyディレクトリのコピーですが、クロスビルド環境用の設定ファイルが存在する点が異なります。

```
/home/username/poky_sdk/
├── bitbake.lock
├── buildtools
├── cache
├── conf
├── downloads
├── environment-setup-cortexa7hf-neon-vfpv4-poky-linux-gnueabi  # クロスビルド開発用の設定ファイル
├── layers
├── preparing_build_system.log
├── sdk_tree.txt
├── site-config-cortexa7hf-neon-vfpv4-poky-linux-gnueabi
├── sstate-cache
├── sysroots
├── tmp
├── version-cortexa7hf-neon-vfpv4-poky-linux-gnueabi
└── workspace
```

クロスビルド用の`environment-setup-cortexa7hf-neon-vfpv4-poky-linux-gnueabi`には、
コンパイル時に必要な環境変数が記載されています。以下に内容の一部を示します。

```~/poky_sdk/environment-setup-cortexa7hf-neon-vfpv4-poky-linux-gnueabi.(一部)
(省略)
export CC="arm-poky-linux-gnueabi-gcc  -march=armv7ve -marm -mfpu=neon-vfpv4  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT"
export CXX="arm-poky-linux-gnueabi-g++  -march=armv7ve -marm -mfpu=neon-vfpv4  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT"
export CPP="arm-poky-linux-gnueabi-gcc -E  -march=armv7ve -marm -mfpu=neon-vfpv4  -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT"
export AS="arm-poky-linux-gnueabi-as "
export LD="arm-poky-linux-gnueabi-ld  --sysroot=$SDKTARGETSYSROOT"
export GDB=arm-poky-linux-gnueabi-gdb
(省略)
```


上記の環境変数を設定すれば、
gcc使用時にクロスコンパイル用の面倒なオプションを記述する必要がなくなります。
設定方法方は、SDKインストール時のログにも示されていますが、念のため、以下にコマンドを示します。

```
$ cd ~/poky_sdk/
$ source environment-setup-cortexa7hf-neon-vfpv4-poky-linux-gnueabi
SDK environment now set up; additionally you may now run devtool to perform development tasks.
Run devtool --help for further details.
```

#参考
[Yocto Project公式サイト](https://www.yoctoproject.org/)
[公式リファレンス](http://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html)
[Yocto for Raspberry Pi(Packt出版)](https://www.packtpub.com/hardware-and-creative/yocto-raspberry-pi)
[Building Raspberry Pi Systems with Yocto](http://www.jumpnowtek.com/rpi/Raspberry-Pi-Systems-with-Yocto.html)