SMLUnitをPoly/MLに対応した
SMLUnitというSML用ユニットテストライブラリをPoly/ML5.8から使えるようにしました。
makeと上手く連携するMakefileが書けたので満足です。
ブランチはここ> https://github.com/eldesh/SMLUnit/tree/support/polyml *1
使い方はReadmeに書いたけど、Poly/MLの機能の解説もしつつここにもまとめておこう。
使い方
まずREPLでの使い方。
Poly/MLは PolyML.make: string -> unit
という関数にディレクトリ名を与えると、そのディレクトリ以下の ml_bind.ML
みたいな名前のファイルを探してきて読み込みます。
さらに ml_bind.ML
の中で structure, signature, functor
に言及すると、それらと同名のファイルを探してきて読み込みます。
ちゃんとmake
なので(?)2回目以降は前回読んだ時から更新されたファイルだけ読み込んでくれるので便利です。
SMLUnit$ poly --eval 'PolyML.suffixes := ".sig"::(!PolyML.suffixes)' > PolyML.make "src/main"; Making main Making SMLUnit .. structure SMLUnit: SMLUNIT val it = (): unit
--eval
には PolyML.make
が探すファイル名の拡張子を追加するコードを渡しています。
こうしておくと未知のシグネチャ名に言及したときに .sig
ファイルも探してくれます。
ビルド
SMLUnitはユニットテストライブラリなので当然他のライブラリからも参照したいですね。
でも実はPolyML.make
は、その時点でのカレントディレクトリからの相対パスでファイルを探すので*2、無関係なディレクトリから参照しづらいという問題があります。
そこでコンパイルした結果をモジュールエクスポートという機能を使って書き出しておきます。
SMLUnit$ make -f Makefile.polyml echo "" | poly -q --error-exit --eval 'PolyML.suffixes := ".sig"::(!PolyML.suffixes)' \ --eval 'PolyML.make "src/main"' \ --use export.sml \ --eval 'PolyML.SaveState.saveModule ("libsmlunit.poly", SMLUnit)' Making main Making SMLUnit .. Created structure SMLUnit
デフォルトターゲットをmake
すると、PolyML.SaveState.saveModule
を使ってSMLUnitの公開するモジュールが ./libsmlunit.poly
に書き出されます。
このファイルは普通にREPLからも読めますのでライブラリのデバッグなどに便利です*3。
> PolyML.loadModule "./libsmlunit.poly"; signature ASSERT = sig .. signature TESTRUNNER = sig type parameter val runTest: parameter -> Test.test -> unit end val it = (): unit
(他ライブラリからの)使い方
Poly/MLでプログラムの最終結果(実行ファイル)を得るには、まずPolyML.export: string * (unit -> 'a) -> unit
という関数に適切なオブジェクトファイル名とエントリーポイントになる関数(要はmain関数)を渡します。
その際あらかじめ依存しているライブラリ(libsmlunit.poly)をロードしておきます:
> PolyML.loadModule "/path/to/libsmlunit.poly"; (* 依存している SMLUnit を読み込む *) > PolyML.make "hoge/src"; (* 利用側のコードを読み込む *) > PolyML.export ("libhoge.o", Main.main); (* main: unit -> unit をエクスポート *)
そしてエクスポートしたオブジェクトファイルをpolyc
コマンドでリンクして完了です。
$ polyc -o hoge libhoge.o
./hoge
..