Raspberry Pi が使っていた ARM 世代の歴史を見ると、本当に古いチップで驚く
Raspberry Pi B+ が出た 2014 年時点でも、採用されていた ARM1176 コアは 2003 年製で、すでに 11 年前のものだった
なので、より新しい Raspberry Pi のような別プラットフォームでビルドするときに、互換性のあるコードを作るにはアーキテクチャフラグを明示する必要があるかもしれない、というのは不思議ではない
ただし Raspberry Pi B+ 自体でビルドする場合にも正しいアーキテクチャがデフォルトで選ばれないなら、ディストリビューション側のデフォルト値の 設定ミスのように見える
初代 Pi は、TV ボックス向けに使われて余ったチップを使っていたと記憶している
そういう製品は価格の都合で、必要以上の演算性能を載せることはほとんどない
そもそも 低価格コンピュータとして作ろうとしていた製品だった
実際に B+ でビルドしたわけではない
記事には「ずっと速い Pi 4B であるビルドホストからバイナリを持ってきて、この古い機器で実行しようとしたら illegal instruction になった」とある
これは Windows 11 上で最新の MSVC でビルドした .EXE を、Windows XP が入った古い PC で実行しようとするのに似ている
おそらく Pi 4B で動かしている Pi ディストリビューション全体も B+ では動かない可能性が高く、カーネルまで同じ方式でコンパイルされているかもしれない
1件のコメント
Hacker News のコメント
Raspberry Pi が使っていた ARM 世代の歴史を見ると、本当に古いチップで驚く
Raspberry Pi B+ が出た 2014 年時点でも、採用されていた ARM1176 コアは 2003 年製で、すでに 11 年前のものだった
なので、より新しい Raspberry Pi のような別プラットフォームでビルドするときに、互換性のあるコードを作るにはアーキテクチャフラグを明示する必要があるかもしれない、というのは不思議ではない
ただし Raspberry Pi B+ 自体でビルドする場合にも正しいアーキテクチャがデフォルトで選ばれないなら、ディストリビューション側のデフォルト値の 設定ミスのように見える
そういう製品は価格の都合で、必要以上の演算性能を載せることはほとんどない
記事には「ずっと速い Pi 4B であるビルドホストからバイナリを持ってきて、この古い機器で実行しようとしたら illegal instruction になった」とある
これは Windows 11 上で最新の MSVC でビルドした .EXE を、Windows XP が入った古い PC で実行しようとするのに似ている
おそらく Pi 4B で動かしている Pi ディストリビューション全体も B+ では動かない可能性が高く、カーネルまで同じ方式でコンパイルされているかもしれない
記事や本文では明確に扱われていないように思うが、これは バグではないのか?
LLVM のバグを探してみると、ほぼ同じ問題に見える項目があったが、2012 年のバグでクローズされている。最後のいくつかのコメントを見ると、実際には修正されていない可能性もありそうだったが、ざっと見ただけなので誤解している可能性もある
https://github.com/llvm/llvm-project/issues/13989
見直してみると、記事の最後でターゲットを明示的に渡せば動くプログラムが得られると書いてあった。だとすると一種の設定バグのようで、Unix ではデフォルトターゲットは現在のプロセッサになると思っているが、確信はない
リンクしたバグは、ターゲットを正しく設定しても間違ったコードを生成していた問題だったようで、幸い今はそういう状況ではないらしい
Rachel の問題は、コンパイラに armv6 をターゲットにするよう伝えることで解決したので、そのバグはすでに修正済みで、今回の問題とは別物に見える
私が関わっているデータベースである ClickHouse は、かなり古いハードウェアとの互換性を保つためにそれなりに努力している
標準の ARM バイナリは 2016 年の Armv8.2 を要求し、Raspberry Pi 2 以降のモデルで利用できる。x86 バイナリは、高速 CRC のための SSE4.2 と pclmul* 命令を備えた 2010 年前後のハードウェアで実行できる
Armv8.0 と SSE2 しかないシステム向けのバイナリもビルドしているが、CI ではテストしていない。高速インストールスクリプトが対象ホストに合うバイナリをダウンロードして展開してくれる
後方互換性と、最新 AArch64 世代の CPU 機能の活用との間でバランスを取るのは、全体として難しいと感じる
https://en.wikipedia.org/wiki/AArch64
予算が厳しい組織、たとえば新興国の大学や、ハードウェアをアップグレードする余裕のないホビーユーザーが驚くほど多かった
技術的には、/proc/cpuinfo の CPU フラグが、コンパイラに渡す -march= フラグと常に対応するわけではない点がかなり厄介だった。たとえば "lrcpc" と "rcpc" のように異なる形で現れる
これを正しく動かすには、実質的に 2 種類のフラグ集合を管理する必要がある
問題は、bookworm の現在の clang-13 パッケージで 設定ターゲットが変わったことである可能性が高そう
具体的には、bullseye と clang-11 ではデフォルトターゲットが armv6k-unknown-linux-gnueabihf だが、bookworm と clang-13 では arm-unknown-linux-gnueabihf になっている
あるいは LLVM 側で、そのビルド設定のデフォルト値が変わったのかもしれない
ただし [1] と [2] を比較すると、rules ファイルに「DEB_HOST_ARCH が armhf なら LLVM_HOST_TRIPLE を armv6k に設定する」というすっきりしたテストがあり、ビルド設定の変更を確認しているように見える
[1] http://raspbian.raspberrypi.org/raspbian/pool/main/l/llvm-to...
[2] http://raspbian.raspberrypi.org/raspbian/pool/main/l/llvm-to...
意図的な変更ではなさそう
周辺のコメントで /etc/env.d/gcc に言及されていたように、環境から情報を読み取る方式である可能性はかなりある
デフォルトのトリプルは、clang がより具体的な情報を見つけられない、または渡されない場合、arm-unknown-linux のような値になるはずだが、より具体的なターゲットを知らせるメカニズムが壊れているように見える
これは ARMv6 ビルドボットがないという意味かもしれないし、ビルドボットはあるが、そこでは暗黙の設定がまだうまく機能しているという意味かもしれない
LLVM は本当に優れたクロスコンパイラ。どのターゲット上からでも、どのターゲット向けにも大きな問題なくビルドできる
Clang はそれよりは魅力に欠ける。ターゲットサポート込みでビルドされていて、どのターゲット向けにビルドするかを正しく伝えられれば、おそらく正しく処理する。この記事でも推測は外れていたが、より多くの情報を与えると正しく動作した
ランタイムライブラリの事情はさらに悪い。armv4 のようなターゲット向けにビルドしたとしても、それに合う libc などを見つける必要があり、そのライブラリやヘッダーの場所をコンパイラに知らせる必要があるかもしれないが、この部分はいまだに詳細が明確ではない
古い Synology NAS 向けバイナリをビルドするときに似た問題に遭遇した
clang/clang++ は /etc/env.d/gcc からターゲットフラグとプロファイルを読み取り、それを正しく保つのは OS の役目
この OS ではその管理がうまくいっていないように見える
さらに古い armv4 アーキテクチャベースの私の Gentoo ARM SBC は、最新の gcc/clang アップデートでもずっと問題なく動いている
grep CTARGET /etc/env.d/gcc -r/etc/env.d/gcc/armv4tl-softfloat-linux-gnueabi-11.3.0:CTARGET="armv4tl-softfloat-linux-gnueabi"Clang にそのディレクトリを読む機能があるわけではないので、他のディストリビューションにもあると仮定すべきではない
Gentoo のコンパイラ設定が CTARGET 環境変数を読んでターゲットを選び、Gentoo がその値を設定するために /etc/env.d を使っているだけ
記事には Debian なのか Raspbian なのか、Debian なら armel ポートなのか armhf ポートなのかが書かれていない
その情報なしに LLVM がどの命令セットでコンパイルしているかを論じてもあまり意味がない。それは LLVM のネイティブターゲット設定に依存する問題だから
ちなみに Debian の llvm-toolchaim-snapshot は、今でも ARMv5T をベースラインとする armel をサポートしている。ただし現在の LLVM の OpenMP ライブラリには別のバグがあり、ビルドは成功しない
これは本当に変。クロスコンパイラとして使えという話ではないので、理論上は ホストとターゲットが同じであるべき
おそらくイメージは Raspbian だと思う。そう仮定しない理由はなさそう
dpkg-architectureコマンドの出力と/etc/os-releaseファイルの内容が分かると役に立ちそうそれがないと有用なコメントをするのは難しい
タイトルが残念ながら扇情的
これは デフォルトターゲットの変更であり、clang は今でも Pi B+ 向けバイナリをビルドできる
アーキテクチャを明示的に指定すればよいだけ。なのでデフォルト設定の変更であることがより明確に伝わるよう、タイトルを少し変えたほうがよさそう
ARM でプログラムがなぜ実行されないのかをデバッグするときは、だいたいこういう感じでアプローチすればよさそうで興味深い
コンテナ内で実行できない Unity Linux ビルドがあるのだが、Docker 実行時に amd64 フラグを渡しても、Unity mono が利用できないシステムコールをしようとする
回避方法を見つけたので、まだデバッグはしていない。開発モードを有効にしてビルド設定を変え、mono を使わないようにした
いつかもっと学ぶために掘り下げ直したい