みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

YoctoProject やってはダメな実装の例

はじめに

実際にgithubで公開されているレイヤで見逃せない悪い実装例があったので紹介する。 特定の個人や団体を批判するものではなく、実装、および設計思想に問題があるというための例示であることを強調しておく。

今回取り上げるのはradxaのmeta-rockchip。 「radxaの」と書いたのは、meta-rockchipが複数あり一つはYoctoProjectの管理下にあるから。

決して実装のクォリティが低いとかそういうことではなく、YoctoProjectを使用する上で間違った設計手法を取り入れているということの指摘だと受け取っていただきたい。

YoctoProjectの前提

YoctoProjectを使用する上で最初に知っておいてほしい前提が「What I wish I’d known about Yocto Project」に記載されている。

その中でも重要なのが下記になる。

Never modify the POKY layer. Never. Ever. When you update to the next release, you’ll lose all of your work. ALL OF IT.

これはpokyレイヤを直接編集してはいけない。ということを示している。なぜならpokyは継続的にメンテナンスされていてここを直接編集すると必ずマージ作業が発生するから。「you’ll lose all of your work. ALL OF IT.」は、あなたの修正は全て無かったことになるよ!という表現だが、結局はそういうことを意図していると思う。

転じて、既存のレイヤをいじってはいけない。既存のレイヤの振る舞いを変えたい時はYoctoProject/OpenEmbeddedが提供している、bbappendなどの仕組みを使って必要な部分を上書きしなさいという前提となる。 それはつまり、自分がレイヤを作成するときに他の人が上書きすることを前提に設計しなくては行けないということになる。自分の書いたレイヤが他の人が書いたレイヤに悪影響を及ぼしてはいけない。作法に則った書き方をしたレイヤならその作法から推測できる振る舞いをしなくてはならないということにもつながる。

radxaのmeta-rockchipの例

ここで例示するのはカーネルのレシピが参照しているlinux-rockchip.inc

linux-rockchip.inc

linux-rockchip.incの内容は下記の通り。

# Copyright (C) 2019, Fuzhou Rockchip Electronics Co., Ltd
# Released under the MIT license (see COPYING.MIT for the terms)

inherit python3-dir

DEPENDS:append = " openssl-native lz4-native ${PYTHON_PN}-native"

LINUX_VERSION_EXTENSION ?= "-rockchip-${LINUX_KERNEL_TYPE}"

PATCHPATH = "${THISDIR}/${BPN}_${LINUX_VERSION}"
inherit auto-patch

KCONFIG_MODE ?= "--alldefconfig"

# Make sure we use /usr/bin/env ${PYTHON_PN} for scripts
do_patch:append() {
    for s in `grep -rIl python ${S}/scripts`; do
        sed -i -e '1s|^#!.*python[23]*|#!/usr/bin/env ${PYTHON_PN}|' $s
    done
}

do_compile:prepend() {
    export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${STAGING_LIBDIR_NATIVE}
}

do_compile_kernelmodules:prepend() {
        export PKG_CONFIG_DIR="${STAGING_DIR_NATIVE}${libdir_native}/pkgconfig"
        export PKG_CONFIG_PATH="$PKG_CONFIG_DIR:${STAGING_DATADIR_NATIVE}/pkgconfig"
        export PKG_CONFIG_LIBDIR="$PKG_CONFIG_DIR"
        export PKG_CONFIG_SYSROOT_DIR=""
    export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${STAGING_LIBDIR_NATIVE}
}

# Hack for rockchip style images
ROCKCHIP_KERNEL_IMAGES = "boot.img zboot.img"
KERNEL_IMAGETYPES:append = " ${ROCKCHIP_KERNEL_IMAGES}"
python () {
    if not d.getVar('KERNEL_DEVICETREE'):
        raise bb.parse.SkipPackage('KERNEL_DEVICETREE is not specified!')

    # Use rockchip stype target, which is '<dts(w/o suffix)>.img'
    d.setVar('KERNEL_IMAGETYPE_FOR_MAKE', ' ' + d.getVar('KERNEL_DEVICETREE').replace('rockchip/', '').replace('.dtb', '.img'));
}

# Force regenerating defconfig
do_kernel_metadata:prepend() {
    rm -f ${WORKDIR}/defconfig
}

# Link rockchip style images
do_install:prepend() {
    for image in ${ROCKCHIP_KERNEL_IMAGES};do
        ln -sf ${B}/${image} ${B}/arch/${ARCH}/boot/
    done

    if [ "x${RK_USE_COMPRESSED_KERNEL}" = "x1" ]; then
        ln -sf zboot.img ${B}/arch/${ARCH}/boot/boot.img
    fi
}

しっかりとした実装に見えるし、問題なさそうだがこの分が問題。

inherit auto-patch

これは自前で実装したクラスである。

auto-patch.bbclass

auto-patch.bbclassの実装はここにある。

実装に問題があるわけではないので省略するが、設計思想がまず大問題である。

このクラスは「特定のディレクトリにパッチがあったらSRC_URIを修正して自動的に適用されるようにする」というものである。 つまり、パッチがあった場合レシピを改ざんするするものになる。 これは「パッチはどうせ増えていくんだからいちいちレシピ修正しなくてもいいよね!」という考え方で設計されたものになる。 一見、問題ないし便利そうに思えるかもしれない。

しかし!!!

このレイヤが提供するパッチに問題があり、このパッチをリバートするパッチを追加した別のレイヤがあった時に、 auto-patch.bbclassがどのタイミングどの順序でパッチをあてるのか確定できないためうまく動かない。 普通にSRC_URIにパッチのパスが書いてあって、レイヤのプライオリティで調整することができれば。 ただ単にそのパッチを取り消す修正は簡単なのに。

いちいちこの実装を解析して、どう動くかを考えてデバッグして。。それでも状況によっては動作が変わる可能性が孕む。 なので、リバートしたいパッチをmeta-rockchipから直接削除するのが一番確実ということになる。

今は修正されているかもしれないが、0001-net-rkwifi-Fix-include-path-error.patchの実装に問題があり、 このパッチをリバートすることで動作するドライバあるというケースがあった。

私はこのパッチをリバートするために、当たり前のように優先度を高くしてリバートパッチをSRC_URIに追加するだけのbbappendを含んだレイヤを作成した。 しかしパッチをあてるタイミングがauto-patch.bbclassの振る舞いによってdo_patchでは「そんなコミットはないからリバートできない」というエラーになってしまうのだ。

まとめ

原文

ちゃんとレシピ書け。横着すんな。 あと、横着するのは構わないけどルールは守れ。 変なbbclass自作すんな。ルールを理解してからにしろ。 他のレイヤがお作法守っているのに、ちゃんと動かないようなレイヤを作るな。

あまりにもひどいので要約。

  • レシピの修正をめんどくさがらない
  • めんどくさいからとなにか工夫する場合でもルールは守ったほうが良い
  • bbclassを自作するのは、ある程度習熟してから。また、ルールは守ってほしい。
  • 他のレイヤがお作法を守っているのにうまく動かなくなるような機能は追加してはいけない