SL コマンドの Yocto レシピを作る


Yocto Project というのは組込み用に Linux イメージを構築する仕組みです。[昨日](http://qiita.com/propella/items/070c7a29be1158d605d2)に引き続き本日は [SL](https://github.com/mtoyoda/sl) という冗談コマンドを Yocto レシピ化します。

SL は一見 Make 一発の簡単なコマンドですが、依存ライブラリがあったり、クロスコンパイル用にパッチをあてる必要があったり意外と落とし穴があって入門には最適でした。

## 前提

* [source oe-init-build-env](http://www.yoctoproject.org/docs/2.3/mega-manual/mega-manual.html#building-an-image-for-emulation) 等で Yocto 環境が出来ている事を前提とします。
    * (AGL の場合 `source meta-agl/scripts/aglsetup.sh -m m3ulcb agl-demo agl-devel`)
* ~/bbtest/meta-sl にテスト用のレイヤとレシピを作ってゆきます。

## レイヤの登録

bitbake が今から作るレイヤを発見するようにします。source の直後 build ディレクトリからみて conf/bblayers.conf と conf/local.conf を書き換えます。

    $ echo "BBLAYERS =+ '$HOME/bbtest/meta-sl'" >> conf/bblayers.conf ### Bitbake に meta-sl が見えるようにする。
    $ echo 'IMAGE_INSTALL_append = " sl "' >> conf/local.conf ### SD イメージに sl をインストールする

## レシピ作成

まず yocto-layer create というコマンドでレイヤの雛形を作ります。

```sh
$ cd ~/bbtest
$ yocto-layer create sl
Please enter the layer priority you'd like to use for the layer: [default: 6] 
Would you like to have an example recipe created? (y/n) [default: n] 
Would you like to have an example bbappend file created? (y/n) [default: n] 

New layer created in meta-sl.

Don't forget to add it to your BBLAYERS (for details see meta-sl/README).
```

レシピに必要な情報を書いてゆきます。

```sh
$ mkdir -p ~/bbtest/meta-sl/recipes-sl/sl
$ cat << 'EOF' > ~/bbtest/meta-sl/recipes-sl/sl/sl_0.1.bb
SUMMARY = "SL(1): Cure your bad habit of mistyping"
SECTION = "examples"
LICENSE = "Original"
LIC_FILES_CHKSUM = "file://LICENSE;md5=74e9dd589a0ab212a9002b15ef2b82f0" ### ライセンスファイルには チェックサムが必要

SRCREV = "923e7d7ebc5c1f009755bdeb789ac25658ccce03" ### git からのソース取得には特定のリビジョンを指定
SRC_URI = "git://github.com/mtoyoda/sl.git"

S = "${WORKDIR}/git/"

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

* [LIC_FILES_CHKSUM](http://www.yoctoproject.org/docs/2.3/ref-manual/ref-manual.html#var-LIC_FILES_CHKSUM): ライセンスとそのチェックサムを指定する。
    * チェックサムを求めるには、最初に `LIC_FILES_CHKSUM = "file://LICENSE;md5=xxx"` のように適当な値を書くとエラーで正しい値を教えてくれる。
    * file:// から始まる URL は [FILESPATH](http://www.yoctoproject.org/docs/2.3/ref-manual/ref-manual.html#var-FILESPATH) からファイルを検索する。
    * FILESPATH は [base.bbclass](http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/meta/classes/base.bbclass#n76)等で定義されている。
        * レシピが recipe-xx/xx だとすると、recipe-xx/xx/xx や recipe-xx/xx/files 等を指す。
        * 不明瞭な検索パスが多く醜悪な仕様だ。
* [S](http://www.yoctoproject.org/docs/2.3/ref-manual/ref-manual.html#va-S): 展開したソースコードの位置を指示する。
    * これも展開位置が暗黙のうちに "${WORKDIR}/git/" と決まっているのにわざわざユーザに指定させる醜悪な仕様だ。
* [5.3.21.3. Makefile-Based Package](http://www.yoctoproject.org/docs/2.3/dev-manual/dev-manual.html#new-recipe-makefile-based-package) に Makefile ベースのプロジェクト作成法が書かれてある。
    * Makefile が存在する時、do_compile ステップは不要らしい。
    * [base_do_compile()](http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/meta/classes/base.bbclass#n320) に Makefile 起動が定義されてあるが、どのようにこの関数が呼ばれるのか分からなかった。

ここで bitbake-layers show-layers や bitbake-layers show-recipes で設定を確認すると、以下のように meta-sl が登録されている事が分かります。

```sh
$ bitbake-layers show-layers ### このプロジェクトに登録されているレイヤを一覧する。
layer                 path                                      priority
==========================================================================
meta-sl               /home/tyamamiya/bbtest/meta-sl            6
...

$ bitbake-layers show-recipes ### アルファベット順にレシピが表示される。凄く時間がかかる。
...
sl:
  meta-sl              0.1
...

```

いよいよ bitbake sl を実行します。案の定エラーになります。

```sh
$ bitbake sl
ERROR: sl-0.1-r0 do_package: objcopy failed with exit code 256 (cmd was 'aarch64-agl-linux-objcopy' --only-keep-debug 'xxx/build/tmp/work/aarch64-agl-linux/sl/0.1-r0/package/usr/bin/sl' 'xxx/build/tmp/work/aarch64-agl-linux/sl/0.1-r0/package/usr/bin/.debug/sl'):
aarch64-agl-linux-objcopy: Unable to recognise the format of the input file `xxx/build/tmp/work/aarch64-agl-linux/sl/0.1-r0/package/usr/bin/sl'
ERROR: sl-0.1-r0 do_package: Function failed: split_and_strip_files
ERROR: Logfile of failure stored in: xxx/build/tmp/work/aarch64-agl-linux/sl/0.1-r0/temp/log.do_package.3909
ERROR: Task 11 (/home/tyamamiya/bbtest/meta-sl/recipes-sl/sl/sl_0.1.bb, do_package) failed with exit code '1'
```

## パッチの作成

このエラーがわかりづらく非常に苦労しました。念のため出来上がった usr/bin/sl を file で調べると x86-64 のバイナリになっていました。よもやと思い元のソースコードを調べると、Makefile の中で CC=gcc と $(CC) を上書きしてしまっています。ここは簡単な Makefile のパッチが必要という事です。

git 上のプロジェクトのパッチを作成するには git format-patch というコマンドを使う。詳細は省略するが、適当なブランチを作って修正し、`git format-patch master` とやると master との差分が出来るのでこれをレシピに組み込む。パッチは FILESPATH が通っている場所、例えば files 等に置く。

```sh
$ mkdir -p ~/bbtest/meta-sl/recipes-sl/sl/files

$ cat << 'EOF' > ~/bbtest/meta-sl/recipes-sl/sl/files/0001-Remove-assignment-to-CC.patch 
From c8fb0773214039b46a66675fa4e18d38beaf3a1b Mon Sep 17 00:00:00 2001
From: Takashi Yamamiya <tyamamiya@xevo.com>
Date: Tue, 6 Jun 2017 12:37:28 +0900
Subject: [PATCH] Remove assignment to CC

---
 Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Makefile b/Makefile
index c3005d2..21687fb 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,6 @@
 #      Last Modified: 2014/03/31
 #==========================================
 
-CC=gcc
 CFLAGS=-O -Wall
 
 all: sl
-- 
2.7.4
EOF
```

パッチを取り込むよう修正したレシピは以下のようになる。SRC_URI に追加するだけ。

```sh
cat << 'EOF' > ~/bbtest/meta-sl/recipes-sl/sl/sl_0.1.bb
SUMMARY = "SL(1): Cure your bad habit of mistyping"
SECTION = "examples"
LICENSE = "Original"
LIC_FILES_CHKSUM = "file://LICENSE;md5=74e9dd589a0ab212a9002b15ef2b82f0"

SRCREV = "923e7d7ebc5c1f009755bdeb789ac25658ccce03"
SRC_URI = "git://github.com/mtoyoda/sl.git"
SRC_URI += "file://0001-Remove-assignment-to-CC.patch" ### ここにパッチを追加する。

S = "${WORKDIR}/git/"

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

DEPENDS = "ncurses" ### 警告が出るので依存ライブラリを追加

EOF
```

最初 DEPENDS が無かったので以下のような警告が出ていました。

```
WARNING: sl-0.1-r0 do_package_qa: QA Issue: sl rdepends on ncurses-libncurses, but it isn't a build dependency, missing ncurses in DEPENDS or PACKAGECONFIG? [build-deps]
WARNING: sl-0.1-r0 do_package_qa: QA Issue: sl rdepends on ncurses-libtinfo, but it isn't a build dependency, missing ncurses in DEPENDS or PACKAGECONFIG? [build-deps]
```

これで完成です。イメージ全体を作って適当な ARM マシンで動かします。