SML#の非分割コンパイル(ができない) [SML]
いま取り組んでいる個人的なSMLのプロジェクトで、できるだけ多くの複数のSMLコンパイラでビルドできるようにしたいと思っている。
SMLの処理系はビルドシステムもばらばらだし分割コンパイルもすべての処理系でできるわけではない。
ビルド方法の違いはsconsスクリプトを書いて吸収し、分割コンパイルについては低いバーに合わせなければならないから一括コンパイルで統一する。
いまのところMltonとPoly/MLに対応できている。Mltonはソースのリストからいったんmlbファイルを作ってビルドする。Poly/MLで実行ファイルを作る方法はちょっと変わっていて、対話シェル上でコンパイルされたものPolyML.exportという関数を使って吐き出すと実行ファイルになるので、sconsから標準入力経由でuseを流し込んで最後にexportする。
それで、次にSML#にも対応したいと思っているのだけどこれが以外に厄介だ。
SML#は「真の分割コンパイル」をサポートしている。だから、あるソースを他のコンパイル単位とは独立にコンパイルできる。このとき他のコンパイル単位内の関数なりがどのようなプロトタイプ(C言語風にいうと)を持っているかわからないとバイナリを生成できないので、その情報は提供してあげる必要があって、smiファイルにそういう情報を書く。これはCでいうヘッダファイル(の中のプロトタイプ宣言)に相当する。
ここまでは別によくて、そういうものなんだろうと思う。しかし今私は分割コンパイルという贅沢品をあきらめているので、一括でコンパイルできればよい。分割コンパイルという要件がなければ理屈上はsmiファイルを書く必要はないはずだ。コンパイラは自分が今のセッション中にコンパイルした関数のプロトタイプを知っているので、その関数に依存する関数をコンパイルするときにはその情報が利用できるはずだ。
しかしSML#はどうもそのようなsmiファイルを書かずに一括コンパイルするというやり方には対応していないようだ。たとえばsmlsharpコマンドに複数のsmlファイルを引数として与えると「cannot specify multiple .sml/.smi files in link mode」と返ってきてしまう。複数指定できないとなると1つずつ指定しなければならないが、それはつまり分割コンパイルということなのでsmiが必要になる。smiファイルに必要な_require文を書くことによってそれらをたどってリンクしてくれるという機能もあるんだけど_requireできるのはsmlでなくsmiだけなのでやっぱりsmiが必要になる。
しかしsmiファイルを書くのは正直言って面倒くさいのだ。分割コンパイルのために必要だというのはいいけど、分割コンパイルをあきらめたら書かなくてもいいようにしてほしい。大体SMLで書かれたライブラリをSML#から利用しようと思ったらそのライブラリの全部のソースにsmiを書かなければならないのだろうか。せめて自動生成してくれれば…
一応最後の手段として、ソースを全部catで連結したバンドルファイルを作ってそれをコンパイラに渡すというのはある。でも、コンパイラが出すエラーの行番号はバンドルファイルのものになってしまうので、あまり役に立たなくなってしまうし、なによりスマートじゃない。
SMLの処理系はビルドシステムもばらばらだし分割コンパイルもすべての処理系でできるわけではない。
ビルド方法の違いはsconsスクリプトを書いて吸収し、分割コンパイルについては低いバーに合わせなければならないから一括コンパイルで統一する。
いまのところMltonとPoly/MLに対応できている。Mltonはソースのリストからいったんmlbファイルを作ってビルドする。Poly/MLで実行ファイルを作る方法はちょっと変わっていて、対話シェル上でコンパイルされたものPolyML.exportという関数を使って吐き出すと実行ファイルになるので、sconsから標準入力経由でuseを流し込んで最後にexportする。
def compile_poly(env, target, source): p = Popen(shlex.split('poly -q --error-exit'), stdin=PIPE, stdout=PIPE) script = '' for s in source: script += 'use "%s";\n' % s script += 'PolyML.export("%s", main);' % target[0] p.communicate(script) return None
それで、次にSML#にも対応したいと思っているのだけどこれが以外に厄介だ。
SML#は「真の分割コンパイル」をサポートしている。だから、あるソースを他のコンパイル単位とは独立にコンパイルできる。このとき他のコンパイル単位内の関数なりがどのようなプロトタイプ(C言語風にいうと)を持っているかわからないとバイナリを生成できないので、その情報は提供してあげる必要があって、smiファイルにそういう情報を書く。これはCでいうヘッダファイル(の中のプロトタイプ宣言)に相当する。
ここまでは別によくて、そういうものなんだろうと思う。しかし今私は分割コンパイルという贅沢品をあきらめているので、一括でコンパイルできればよい。分割コンパイルという要件がなければ理屈上はsmiファイルを書く必要はないはずだ。コンパイラは自分が今のセッション中にコンパイルした関数のプロトタイプを知っているので、その関数に依存する関数をコンパイルするときにはその情報が利用できるはずだ。
しかしSML#はどうもそのようなsmiファイルを書かずに一括コンパイルするというやり方には対応していないようだ。たとえばsmlsharpコマンドに複数のsmlファイルを引数として与えると「cannot specify multiple .sml/.smi files in link mode」と返ってきてしまう。複数指定できないとなると1つずつ指定しなければならないが、それはつまり分割コンパイルということなのでsmiが必要になる。smiファイルに必要な_require文を書くことによってそれらをたどってリンクしてくれるという機能もあるんだけど_requireできるのはsmlでなくsmiだけなのでやっぱりsmiが必要になる。
しかしsmiファイルを書くのは正直言って面倒くさいのだ。分割コンパイルのために必要だというのはいいけど、分割コンパイルをあきらめたら書かなくてもいいようにしてほしい。大体SMLで書かれたライブラリをSML#から利用しようと思ったらそのライブラリの全部のソースにsmiを書かなければならないのだろうか。せめて自動生成してくれれば…
一応最後の手段として、ソースを全部catで連結したバンドルファイルを作ってそれをコンパイラに渡すというのはある。でも、コンパイラが出すエラーの行番号はバンドルファイルのものになってしまうので、あまり役に立たなくなってしまうし、なによりスマートじゃない。
2013-11-04 00:27
nice!(0)
コメント(0)
トラックバック(0)
コメント 0