最近はNix on raspberry pi zero をやった

イントロ

raspberry pi zeroをちょっと前に2枚買ったのが特に用途がない

強いて用があるとすれば、この前買ったserial通信経由でデータが取れるco2計測器がLinuxの方が読みやすそうだなってぐらい。 これはこのco2計測器が悪いわけではなく、macにマウントされるserial device?がちょっといまいちな挙動をしているからだ。

Amazon.co.jp: 国内生産 日本製 二波長CO2センサー搭載マイコン EPEA-CO2-NDIR-08 PC連携可 二波長NDIR方式 Dual Beam CO2モニター 二酸化炭素濃度計 : 産業・研究開発用品

というわけで 何かと開発する上で便利なので、Raspberry Pi OSにnixをいれていく。

余談だが、rasipbian OSはRaspberry Pi OSに名前が変わっていた。

install

Nixをいれるのは適当にやってもらっていいが、以下の行に注意する必要がある

nix/install.in at master · NixOS/nix · GitHub

"$(uname -s).$(uname -m)" の実行結果が Linux.armv6l_linux になることを期待しているが、 少なくとも自分の環境では Linux.armv6l になる

これは Linux.armv6l_linux が返ってくる環境が世の中にあるのかわからないのでバグなのかわからないが、armv6lのRaspberry Pi OSにNixを入れようとしている人間がzeroに近いことを演繹させてくれる有力な証拠である。

ちなみに NixOS on raspberry pi zeroをやっている人間はGitHubを見た感じでは何人かいることが観測できたので、そのうちやると思う。

build on pi

普通の環境では(ここでいう普通の環境とはflake-utilsのdefaultSystemsとか)「はい!あとはプログラムを書いて終わり!」となるが、ここはarmv6l、一切のcacheが降ってこない砂漠地帯、nix-shellが要求するbashInteractiveですらgccのビルドから始まってしまう。

というわけで gccとstdenvのビルドをやっていく。

まぁ時間さえあれば終わるでしょうと思っていてビルドを走らせていたわけだが、途中で止まってしまう。

どうやらメモリが足りなくなってOOMで落ちたっぽいエラーを観測した。足りないのは時間ではなくメモリ。

正直 パイゼロは500Mしかメモリがない、がしかし「20年前のPCでも500Mあったし流石にgccはビルドできるのは?」という気持ちも捨てがたい。そして「SD上にswapを増やしても大変な遅さになってしまうのでは?」と思いパイゼロ上でビルドするのはやめた。

なのでここからはmacでビルドしてラズパイに送る戦略をとる。

build on mac

ところでDockerDesktopという便利なものがある。何が便利かというと、マルチCPUアーキテクチャサポートがある

つまり armv6lのlinuxが豊富なメモリと屈強なCPUを積んだmacで動いてくれるわけだ。

今回は arm32v6/alpine Docker Hub にNixをインストールする戦略をとる。

余談だが NixのcrossCompile機能を使ってやるという手法もあるのだが、derivationが異なってしまう恐れを直感的に感じ取り今回はやめた。 具体的には crossCompileでビルドしたgccを使って ラズパイ上で他のものをビルドすること際に気を使う必要がある可能性を感じた、これは試していないからわからない

話を戻し、まずは bashをビルドしていく。ここで必要なのは時間と忍耐力で、具体的には一晩の時間とmacのファンの音を気にしない心だ。

ここで 一旦 ラズパイの方に できた bashを送る。 nix copy -s --to $ビルドされたbashのpath

送る際に because it lacks a valid signature と言われると思うので、nix.confに require-sigs = false を足して nix-daemonを再起動させる。

おそらく動くと思うし、bashをbuildしようとしてもbuildされずに先程送ったpathが返ってくると思う。もしビルドが始まった場合同一のderivationをビルドしようとしていない可能性が高いと思う。

あとはstdenvをビルドしていく。

あとはビルドするだけと思いきや、ここでstdenvの依存の中に含まれるpcreのtest phaseでコケてしまう。

「そんなわけがないだろう」という気持ちになるが、手元にはすでにコンパイル済みのgccがいるのでラズパイに送りさえすればビルドできるので試してみたところ pcreはビルドできてしまった。

ビルドできてしまったこと自体も「そんなわけがないだろう」という気持ちになったが、pcreがビルドされていれば後はmacのdocker側に持って来ればいいだけなので nix copy --from で持ってくる。もはやキャッチボールだ。

stdenvとbashInteractiveをラズパイ側に送りつけ、 nix-shell できることを確認する。

よかったですね

何故こういったことをやっていたのか忘れてしまったが、おおよそ、私の目的はビルドでプログラムの実行は副作用でしかないので、よかったですね。

pcre debug編

なぜpcreのテストが失敗したのか調査していくと pcregrepの -L オプションで失敗しているようだった。

pcreのソースコードを読んでいくとreaddirの挙動がおかしいように感じたので、疑似的なプログラムを書いて試してみると確かに動かない。

比較するために

  • mac
  • docker(armv6l)
  • docker(x86_64)

の三つの環境で疑似プロを動かしたところ armv6lでだけ動かない。

最初はoverlayfsあたりが悪さをしているのでは?と考えたがどうやら違うらしい。

そもそもマルチCPUアーキテクチャqemuを使っているので、そこら辺のワードと共に探っていくと以下のIssueに行き着いた。

gitlab.com

これは...ダメですね...