OCaml toplevel on Android : マジカルなラクダをAndroidで飼おう


Androidで動作するOCamlインタプリタ OCaml toplevel on AndroidAndroid Market に公開しました。 OCamlのトップレベル(インタプリタ)をAndroid上で操作できます。 enjoy!

仕組み

OCamlトップレベルはネイティブ実行されます(OCamlバイトコード+libcamlrun.a)が、AndroidのアプリはJava VM(dalvikvm)上で動作するため、両者のブリッジが必要でした。 いくつかの方法があり、一部は先日書きましたが、今回の OCaml toplevel on Androidはこのなかのどれでもない、最もイージーな方法を使っています…。
それは 「あるスレッドでocamlトップレベルをバイトコード実行し、標準入出力を介してAndroidアプリのメインスレッドと通信する」という方法です。
stdoutを入力として、stdinを出力としてJava側で開くという荒技が必要でしたが、特段むずかしいわけではなかったです。概要は以前ここに書きました。 この方法は他のLinux CUIアプリをAndroidにポーティングする時にも使えると思います。そんな機会は無さそうですが。

OCamlロスコンパイラ

O'Caml on AndroidO'Caml for iOSはクロスコンパイラです。しかしクロスコンパイラといっても、コンパイラそれ自体はバイトコード実行できるので、実質ストレートなコンパイラと変わることはありません。 必要な条件は

というだけです。 あとはうまくbytecomp をブートストラップできれば、それを使ってasmcomp, asmrun がビルドできます (ということを、O'Caml for iOSを調べて知ったのですが)。
ターゲット環境にホスト環境の構成が混ざるとまずいのですが、ocamlrunの実行には、(すくなくともコンパイル処理に関しては)環境依存の部分がないはずなので、そのようなことは起こらないです。 …たぶん 追記:これはウソ。たとえば 64bit MacOSX では 32bitでocamlrunをビルドする必要がある。64ビット環境で動作するocamlrunで 32ビット向けのコードを吐くocamloptをコンパイルした場合(多分)、正しいバイナリを出力しない。

Android固有のコードは書いてない

今パッチを読んでみて思い出したのですが、 OCaml on Androidでは全く処理系を修正していないです(ネイティブコンパイラ(asmcomp)もインタプリタ(byterun)も、ランタイム(asmrun)も)。 びっくり。 OCaml 3.12 から armeabi がサポートされたので、Androidネイティブのバイナリをそのまま生成できるんですね。 ただ、ライブラリの otherlibs/unix で、Androidには tcdrain がないのでこけていたので、そこを修正した、それだけ。
(じゃ、O'Caml for iOS はなぜasmcomp周りを修正しているのか?気になりますが、調べていません)
苦労したところはむしろMakefile周りでした。 OCamlコンパイルやリンク時にgccを呼ぶので、そこをターゲット環境向けにカスタマイズしなければならない。しかしAndroidのツールチェインはJNI向けにカスタマイズされた複雑なMakefileの集合体になっていて、普通のgccとは勝手が違う。 手探りな所も多く、面倒だったのです。