衝撃のわからなさ

わかってません

PFNから数えて計4年4ヶ月勤めたPreferred Roboticsを退職して、転職活動しながらクロスコンパイル環境を作ったりしています

はじめに

退職しました。
カチャカというロボットに主に組み込みまわりで関わっていて、発売されて満足しました。
量産ロボットに携わるという夢が1つも叶いました。

2ヶ月の有休期間中に、この間に作成したmimic-crossというクロスコンパイル用のDocker imageを 整備していろいろな人に使ってもらえるようにできればと考えています。
この記事ではなぜこのツールを開発した背景を振り返りながら、課題と共に紹介します。

背景

PFN入社からしてすぐ、後にカチャカとなるプロジェクトで ARM CPUボードへのインテグが始まろうとしており、 全体SlackでYoctoを知っている人がいないかという呼びかけがされてました。

私自身はPFVMという自社のNN実行フレームワークを作成するチームに配属されましたが、 ロボットのチームがこのフレームワークを使う橋渡しのようなことをやってもらいたいと言われていました。
記念受験のつもりで受けたPFNに運良く採用してもらえたのは、こういった仕事があったおかげだと思います。 本当に幸運でした。

前職のルネサスエレクトロニクスでYoctoを利用したLinux BSPまわりの業務経験があった私はもちろんすぐに手をあげ、 最終的にはロボットとエフォート50/50で働いていました。

Yocto vs Ubuntu

今組み込みまわりのディストリビューションを選定するとき、主にこれらの系統の2つを比較することになるかと思います。 私の認識ではありますが、簡単にそれぞれの特徴をまとめてみます。

Yocto

  • 特定のHWや製品向けにカスタムがしやすく、組み込みLinuxのベースとして広く使われている
  • 強力なライセンス管理機能があり、ライセンスリスト作成や特定条件を満たさないライセンスの除外などが行いやすい
  • ロスコンパイル向けのレシピを書く仕組みがある
  • ビルド済みパッケージの配布はなく、新規パッケージのビルドに時間がかかることがある
  • 対応していないソフトウェアは新規にbitbake形式のレシピを書く必要がある

Ubuntu

  • カスタムしやすくはない。その代わりHWが違っても環境が揃いやすい
  • パッケージにライセンスが同梱されてはいるが、特に管理機能はない
  • ロスコンパイルを書きやすくする仕組みはない、クロスコンパイルツールは提供されてはいる
  • ビルド済みパッケージが配布されており、非組み込み環境の資産を活用し易い
  • 多くのソフトウェアやライブラリが標準環境として利用しており、独自の手順が必要になりにくい

ディストリビューションを作る側に優しいのはYocto。
アプリケーション開発の観点からは普段のマシンの開発と同じようにUbuntuを使いたいというのが多いのではないでしょうか。

多くのソフトウェアやライブラリはUbuntuをサポート環境として提供していますが、Yoctoはサポートしていません。
カチャカには様々なソフトウェアスタックが搭載されています。
組み込み向けに開発されていない多くのソフトウェアをCPUにデプロイする必要がありました。

またAIは発展速度が早く、新しく出てくるものをすぐに試して開発サイクルを回す必要があります。
新しく出てきたものを手数少なく、エッジデバイスで動かす必要がありました。

ロスコンパイルの問題を解決してUbuntuを採用できれば最高なのだけれど…どうしようというのが検討段階の問題でした。

ロスコンパイルの問題

ロスコンパイル簡単じゃないという話

コンパイラ変えたりarchitecture指定とかすればいいでしょ?と思うかもしれません。 そもそも工数が発生してしまうのは開発サイクルからは好ましくありあますせん。 クロスコンパイルの手順は言語やビルドツールそれぞれで違い、1つ1つ対処していかなくては行けないのです。 依存パッケージを取得するのだってそのままapt-getするのではすみません。

さらに、PythonパッケージがC/C++のビルドを含む場合などはそもそもパッチを当てないとクロスコンパイルできない可能性があります。
開発開始当時はまだnumpyやgrpcなどもaarch64向けにはビルド済みパッケージが提供されておらず、 ロボットという多くのものを扱うプロダクトでこれらのものを1つ1つ確認して対処するのは困難でした。

また自身の開発チームのプロダクトもC++をビルドしてPython Wheelを作成しており対応が必要でした。

こういったケースで以下のような対応策を取られる事が多いかと思います。

ネイティブコンパイル

プロジェクトでもまずネイティブコンパイルが試されてました。
しかしメモリが4GBしかないボードではメモリ不足でビルドを回すことができませんでした。
また(当時は)CI環境でARMインスタンスを使うことができず、Apple SiliconのPCや性能の高いJetsonなどもなく、 利用することができない状態でした。

これは今日の開発においてもクラウドサービスがARM環境を選択できない、あってもARM + CUDAのテストはできない。 開発PCはx86_64マシンであるなどの問題があるかと思います。

QEMUを利用したクロスコンパイル

その他の解決方法として検索するとよく出てくるのはQEMUを使うという方法です。
この方法は遅いという問題があります。 呼び出される命令によりまちまちですが、私はQEMUにした場合およそ10倍ぐらいになるかなと普段見積もっています。

QEMUを使ってビルドはできてたのですが、プロジェクト初期の段階ですでにフルビルドが走ると2日かかっており、 QEMUのように使えて早い環境があれば…!となってました。

mimic-crossを作った

ということで作られたのがこちらです。
(業務時間外で作ってOSSと言い張ってきたので手元にある。)

github.com

これは単純にbinutilsをビルドしている例です。
このようにbaseimageを付け替えることで--platform=linux/arm64つけてクロスコンパイルした場合の時間が、 ubuntu:22.04指定の 434.8sec → 34.6sec に短縮できています。

同じ Dockerfileでnativeビルドもできるため、テストやシミュレータなどはnativeで実行するなどの使い分けもできます。

# FROM ubuntu:22.04
FROM --platform=${BUILDPLATFORM} impactaky/mc-ubuntu22.04-${TARGETARCH}:2.0.0

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        wget ca-certificates \
        binutils gcc make libc6-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists

RUN wget -q https://ftp.gnu.org/gnu/binutils/binutils-2.36.tar.gz \
    && tar xf ./binutils-2.36.tar.gz
WORKDIR /binutils-2.36
RUN ./configure
RUN make -j "$(nproc)"

良いと思ったらsponsorください(直球)

mimic-crossは3年以上前から存在していてカチャカのソフトウェアビルドに使っていたのですが、 すべてbashで書いてしまいメンテが絶望的だったので今年の年末あたりから書き直し始め、 有給休暇の力で一旦旧実装程度まで実装ができました。

まだまだいろいろなコーナーケースがあると思うのですが、イメージを付け替えるだけで試せるので、 ぜひ試して問題など教えていただけると嬉しいです。

対応したい機能はまだまだ大量にあり、今後も継続して開発するつもりです。
3月末までは有給なので特に頑張ります。

このプロジェクトがクロスコンパイルできなくて困っているなどありましたら、 教えていただけると嬉しいです!

今後について

決まってません! このクロスコンパイル環境の開発は継続していきたいと考えており、このような環境の需要を抱えている会社を御存じでしたら、教えていただけると大変ありがたいです。

組み込みソフトウェアというのは多くの会社において、プロダクトを作成するのに必要な1要素であり、 プロジェクトの競争力をもたらすものではなく、枯れた要素を使うべき領域だとされると思います。
しかしながらこの記事で述べたように、AIなどの開発が早く新しい技術と枯れた部分の界面になる領域でもあります。
mimic-crossのようなツールを作成することで、このような界面への課題に取り組むことができればいいなと考えています。

長い記事を最後まで呼んでいただきありがとうございました!