hello-test のレシピを作る
blog
2019-4-1 12:42 JST

hello-test のレシピを作る

hello-test の簡単なレシピを作ります。レシピに先立ち layer を作っておきましょう(詳細はここ)。

試行錯誤した後がそのまま残る hello-test.bbはこちら。

■ ディレクトリ構成

ここでは次のディレクトリ構成を前提にしています。重要なのは言うまでもなく hello-test_1.0.bb です。レシピの名称(hello-test)とバージョン(1.0)は _ で区切ります。

meta-sby-zynq/
    COPYING.MIT
    README
    conf/
        layer.conf
    files/
        sby-fs-perms.txt
    recipes-test/
        hello-test/
            hello-test_1.0.bb
■ 説明とライセンス

DESCRIPTION により説明を SECTION (なくてもよさそう) でカテゴリを指定します。またライセンス情報としてLICENSE と LIC_FILES_CHKSUM を設定します。ここでは、展開後に COPYING.MIT があるものとして WORKDIR を指定しています。

DESCRIPTION="Hello Test Program"
SECTION="sinby/app"
LICENSE="MIT"
LIC_FILES_CHKSUM="file:///${WORKDIR}/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"

poky は meta/files/common-licenses/ に山ほど License を持っているので、そこを指定しても構いません。その場合は file://${COMMON_LICENSE_DIR}/ を使います。

LICENSE="eCos-2.0"
LIC_FILES_CHKSUM="file:///${COMMON_LICENSE_DIR}/eCos-2.0;md5=8c3ea41d02fa9c9253c692351e5940e7"

指定したファイルの一部をライセンスとすることもできます。

LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://COPYING;md5=a3c3499231a8035efd0e004cfbd3b72a 
                    file://src/dmx.c;endline=33;md5=c43f19af03c7c8619cadc9724ed9afe1"
■ ソースファイル

コンパイルの対象となるソースファイルを様々な方法により指定することができます。URI のプロトコルや拡張子を見て、適切な手段でソースを取得することができます。

SRC_URI="file:///tmp/hello.tar.gz"

この例では、汎用性がありませんが、、、次の3つのファイルが入っているものとします。

hello.c
Makfile
COPYING.MIT
■ コンパイルとインストール

hello.c と Makefile を用意した単純なつくりでは、実は何もやってくれません。ログを見るとNOTE: nothing to compileと何っています。Makefile を見つけることができなかったようです。

デフォルトの do_compile はソースを別の場所に展開して configure するのが前提のつくりになっているようです。この回避方法としてはいくつかあります。簡単な方法は Yocto のプロジェクトのサンプルにある
S = "${WORKDIR}"
とソースのディレクトリを WORKDIR にしてしまうことです。しかし、あまりにも汚いのでお勧めしません。

一番良いのは configure を作ることなのでしょうが、そこまで手間をかけたくない場合は次の方法もあります。

do_compile[dirs] = "${WORKDIR}"
do_install[dirs] = "${WORKDIR}"

これは do_compile(そして do_installも)で使用するディレクトリを WORKDIRにするものです。この方法であれば、configure が他のディレクトリにあるとエラーになるパッケージ(たまにある)、でも対応可能(なはず)です。

ここで使用している dirs は Tasks Flagsによると "directories which should be created before the task runs" という意味があります。このカッコの中に入る環境(?)的な変数としてdirs 以外にどのようなものがあるかを次に掲げます。

cleandirs, noexec, nostamp, umask, prefuncs, postfuncs

cleandirs: directories which should created before the task runs but should be empty 
noexec: marks the tasks as being empty and no execution required. These are used as dependency placeholders or used when added tasks need to be subsequently disabled. 
nostamp: don’t generate a stamp file for a task. This means the task is always rexecuted. 
fakeroot: (deprecated): this task needs to be run in a fakeroot environment, obtained by adding the variables in FAKEROOTENV to the environment. 
umask: the umask to run the task under. 
■ do_compile

Makefile(makefile あるいは GNUmakefile) があれば oe_runmake というスクリプトが走り、自働的に make が実行されます。この場合は bb に do_compile() は必要ありません(デフォルトで動作する)。make の引数は "-j 2 -e MAKEFLAGS=" です。2 は PPARALLEL_MAKE で指定した値です。

EXTRA_OEMAKE があれば make の引数として追加されます。次の記述では hello が指定されています。Makefile に hello のターゲットがないと do_compile はエラーとなります。

EXTRA_OEMAKE += "hello"

単純に CC をつかうなら次の方法で可能です。ちゃんとコンパイルされているか心配なので、 printf も追加しておきます。printf の結果は log ファイル tmp/work/armv7a-vfp-neon-poky-linux-gnueabi/hello-test/1.0-r0/temp/log.do_compile に書かれます。

do_compile() {
    ${CC} hello.c -o hello
    printf "compile ${PN}n"
}

task 内はシェルスクリプト風の記述です(bberror とかが使えるところを見るとシェルスクリプトそのものではなさそう)_append や _prepend も通常はシェルスクリプト風なのですが、python のキーワードをつけることで、python のスクリプトにすることができます。蛇足ながら、python から printf の代わりに bb.warn 等でワーニングを表示するという方法があります。しかし、通常のタスクはシェルスクリプトなのでこの方法は使えません。printf はシェルから呼ばれるコマンドなので通常のタスクからは使えますがpython からは使えません。混乱しそうです。

また、シェルスクリプト風の表現のときも、完全にシェルスクリプトという訳ではなさそうです。おそらく、セキュリティの問題でしょう。たとえば、touch が使えるタスクと使えないタスクがありました。各タスクで使える命令(?)に差異がありそう(?再確認必要)なので注意が必要です。

■ do_install

インストールは makefile に install を書いても実行されません。そこで、do_install に明示的にインストールするファイルを書きます。

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

    install -d ${D}${datadir}
    install -m 0444 ${WORKDIR}/hello.c ${D}/${datadir}/hello.c

    printf "datadir ${datadir}n"

    printf "my_sbindir ${my_sbindir}n"
}

なお、ここで実行されるのは ${D} で示されるインストールディレクトリへのインストールであり、パッケージ化ではありません。後述するパッケージでは指定されたディレクトリ以外のファイルはパッケージ内に登録されません。(したがって、できあがったイメージファイル内にもインストールされない)

デフォルトで許諾されているディレクトリは次の通りです。また、${FILESYSTEM_PERMS_TABLES} で指定されるファイルを BBPATH から検索し、それも対象とします。FILESYSTEM_PERMS_TABLES のデフォルトは空でその場合は files/fs-perms.txt を BBPATH の先頭から探し、みつけたらそれ以降は探索を打ち切ります。したがって、自分のメタデータにfiles/fs-perms.txt をおいても探索されません。通常は、files/fs-perms.txt は排他的に使うはずなので
FILESYSTEM_PERMS_TABLES="files/my-fs-perms.txt"
とするのがよいようです(angstrom の方式)。複数のテーブルを使う場合は FILESYSTEM_PERMS_TABLES に空白区切りでファイルを指定します。

    target_path_vars = [    'base_prefix',
                'prefix',
                'exec_prefix',
                'base_bindir',
                'base_sbindir',
                'base_libdir',
                'datadir',
                'sysconfdir',
                'servicedir',
                'sharedstatedir',
                'localstatedir',
                'infodir',
                'mandir',
                'docdir',
                'bindir',
                'sbindir',
                'libexecdir',
                'libdir',
                'includedir',
                'oldincludedir' ]
■ do_package

${D} ディレクトリにインストールされたファイルはパッケージ化のポリシーに従って幾つかのパッケージが作成されます。meta/conf/bitbake.conf に次のように書かれています。

PACKAGES = "${PN}-dbg ${PN}-staticdev ${PN}-dev ${PN}-doc ${PN}-locale ${PACKAGE_BEFORE_PN} ${PN}"
<中略>
FILES_${PN} = "${bindir}/* ${sbindir}/* ${libexecdir}/* ${libdir}/lib*${SOLIBS} 
            ${sysconfdir} ${sharedstatedir} ${localstatedir} 
            ${base_bindir}/* ${base_sbindir}/* 
            ${base_libdir}/*${SOLIBS} 
            ${base_prefix}/lib/udev/rules.d ${prefix}/lib/udev/rules.d 
            ${datadir}/${BPN} ${libdir}/${BPN}/* 
            ${datadir}/pixmaps ${datadir}/applications 
            ${datadir}/idl ${datadir}/omf ${datadir}/sounds 
            ${libdir}/bonobo/servers"

PACKAGES にはパッケージ名が、FILES_<パッケージ名> にはインストールするファイルが書かれます。ここに書かれない場合、次のようにshippedされないというエラーが表示されます。

ERROR: QA Issue: hello-test: Files/directories were installed but not shipped
  /homex
  /usr/share
  /usr/share/dia
  /usr/share/hello.c
  /usr/share/dip
  /homex/dia [installed-vs-shipped]

推奨されない回避方法として INSANE_SKIP を使う方法があります。
INSANE_SKIP_hello-test="installed-vs-shipped"
INSANE の名の通り、推奨されません。

固有のパッケージを追加するには、PACKAGES に追加する形になるでしょう。次の例は libav の例。

PACKAGES += "${PN}-vhook-dbg ${PN}-vhook ffmpeg-x264-presets"

RSUGGESTS_${PN} = "mplayer"
FILES_${PN} = "${bindir}"
FILES_${PN}-dev = "${includedir}/${PN}"

FILES_${PN}-vhook = "${libdir}/vhook"
FILES_${PN}-vhook-dbg += "${libdir}/vhook/.debug"

FILES_ffmpeg-x264-presets = "${datadir}/*.avpreset"
■ タスクの前後に処理を追加

preppend append というキーワードで処理を追加することができます。do_fetch_prepend で do_fetch の前に処理をdo_fetch_appennd で do_fetch の後に処理を追加可能です。

do_fetch_prepend () {
    bb.warn("warn:" + d.getVar('PN', True) + ":" + d.getVar('WORKDIR', True) + d.getVar('S', True))
}

追加されたコードは python のコードに置き換わります(繋げて関数化するようです)。そのため、処理の前のインデントは重要な意味を持ちます(pythonだから)。最初 do_fetch_prepend のインデントにタブを使用したところ、次のエラーが出ました。

rem:build$ bitbake hello-test -c fetch
WARNING: Variable do_fetch contains tabs, please remove these (Yocto/meta-sby-zynq/recipes-test/hello-test/hello-test_1.0.bb)
NOTE: Error during finalise of Yocto/meta-sby-zynq/recipes-test/hello-test/hello-test_1.0.bb
ERROR: ExpansionError during parsing Yocto/meta-sby-zynq/recipes-test/hello-test/hello-test_1.0.bb: Failure expanding variable do_fetch: IndentationError: unindent does not match any outer indentation level (<string>, line 3)

これは do_fetch が4文字の空白によるインデントを使用しており整合性が合わなかったためです。4文字の空白のインデントを使うようにしましょう。

■ タスクの追加

つぎのようにタスクを追加可能です。追加したタスクは次のコマンドで確認可能です。
bitbake -c listtasks hello-test

addtask hello_world before do_configure after do_patch

do_hello_world () {
    printf "hello world ${PR}:${MY_VALUE}:${SRC_URI}n"
    printf "${FILESYSTEM_PERMS_TABLES}n"
}
do_hello_world[doc]="Hello World Script Sample"
■ トライ&エラーとdo_fetch

bb 自身をデバッグするときは bitbake の各タスクを何度も実行することになります。ただし、キャッシュが効くので、BibBake が処理が同じで意味がないと判断したら実行しません。強制的に実行するには-f を使います。

最初にデバッグをするなら do_fetch がお勧めです。

$ bitbake hello-test -c fetch -f

また、混乱してきたら clean あるいは cleanall をして環境をきれいにしておきます。

$ bitbake hello-test -c cleanall

do_<task>_prepend などを有効に使い printf を使いログに情報を吐き出します。各タスクのログは次の箇所にあるので適宜参照します。

tmp/work/armv7a-vfp-neon-poky-linux-gnueabi/hello-test/1.0-r0/ 
         temp/log.do_install
■ おまけ

参考になった bb

oe-core/meta-skeleton/recipes-kernel/hello-mod/hello-mod_0.1.bb