Mosh の Apple Silicon 対応 - 2022夏休み

scheme.org の方から mosh.scheme.org の利用について声をかけていただいた。せっかくなので MoshApple Silicon 対応をしようと思いたった。なお最後のリリースは 0.2.7 で 2011/6/14 に okuoku さんによって行われている。10年以上前である。

C/C++ で書かれたソフトウェアなので新しいアーキテクチャ(=Apple Silicon)でちょいちょいとコンパイルし直せば良い。という話ではない。なぜならば Moshコンパイルには安定して動く Mosh が必要だから。これは gcc のビルドに gcc が必要なのと同じ問題で、bootstrap 問題と呼ばれる。さらにややこしいのが MoshコンパイラScheme で書かれており、これを VM で実行可能なコードにコンパイルするために Gauche で書かれた VM を使っていたりするので厄介である。

Step1: 0.2.7 リリースを雑にビルドする

まずは安定して動く Mosh のバイナリが欲しいのでリリースビルドをビルドする。リリースビルドのビルドには Mosh は必要ない。ビルドするとすぐに GC 周りのエラーになった。10年前の Boehm GCApple Silicon に対応していないので以下のエラーになる。

 "The collector has not been ported to this machine/OS combination."
#   error "The collector has not been ported to this machine/OS combination."
    ^

そこでまず最新の Boehm GC を入手してビルドを試みる。10年の間に Boehm GCディレクトリ構造などが変更になっており Mosh 側の Makefile に変更が必要である。行儀悪いが直接 Makefile を編集してことなきを得た。

続いて奇妙な以下のテストエラー。

(let ((b (make-bytevector 4 0)))
  (bytevector-sint-set! b 0 -1 'little 4)
  (bytevector-uint-ref b 0 'little 4)) : expected 4294967295 but got -1.

詳しく調べてみると Fixnum の 乗算内部で行われているオーバーフローチェックが意図通りうまく動いていないっぽい。

    static Object mul(int n1, int n2)
    {
        const fixedint ret = (fixedint)n1 * n2;

        /* Overflow check from Gauche */
        if ((n2 != 0 && ret / n2 != n1) || !Fixnum::canFit(ret)) {
            Return

const fixedint ret = (fixedint)n1 * n2; この部分の fixedint は int の alias なのだが Apple のドキュメントによると乗算がオーバーフローしたときの動作は不定のようだ。なのでここは int よりも大きなサイズで判断しなければならず。const long ret = (fixedint)n1 * n2; とするのが良さそう。

これを直してめでたく M1 上で動く Mosh がビルドできた。

Step2: macOS 上で bootstrap してみる

さて M1 mac 上で動く安定 Mosh バイナリができたので./gen-git-build.shを実行してみるがエラー。Scheme で書かれたコンパイラを gosh を利用して変換している処理。詳細を調べたり Gauche のバージョンを当時のものに合わせてみたがダメだった。不安定な土台な上で何かをやるのは筋が悪いと気づいた。

Step3: Ubuntu on Docker を試す

Linux 上で Mosh をビルドして動かす方が枯れていて良いだろうということで Docker で。i386 Ubuntu image ではうまくいかなかったので i686 Ubuntu image でやってみたら動いた。依存ライブラリの大半は apt install で取得できるのだが、正規表現ライブラリの oniguruma は特定のバージョンをソースコードからビルド。 ./gen-git-build.sh では autoconf も利用しているのだが正直なところエラーが出たとしても対処できそうにない。

無事 bootstrap できたので tar.gz にまとめてドキュメントを書き。 Release mosh-0.2.8-rc1 · higepon/mosh · GitHub にリリースしておいた。

所感

10年以上前に書かれたコードを新しいアーキテクチャで動かすのは思ったよりも面倒。記憶を頼りにいくつものツール・デバッグを繰り返してやりたいことができたが、最近ではそういう面倒にはほとんど遭遇しない。Tensorflow のバージョン違いで問題が起きるとか、cuda のインストールとか平和なものばかりである。懐かしい気持ちだが、ツールの試行錯誤より本質に時間を使える今の方が良いね。

詳細なログはNotes: Mosh 0.2.7 on M1 mac · Issue #14 · higepon/mosh · GitHubに。