プログラミング言語SML#解説 4.1.0版
28 SML#コンパイラの起動

28.8 典型的な使用例

28.8.1 対話環境

対話環境を起動する最も簡単な方法は,引数なしで smlsharpコマンドを実行することである.

    $ smlsharp

SML#の対話環境からあるCライブラリの関数を対話的に利用したい 場合,そのライブラリの名前を-lオプションで指定する. 例えば,対話環境からzlibライブラリを呼び出したいときは 以下のコマンドを実行する.

    $ smlsharp -lz

C標準ライブラリやPOSIXスレッドライブラリなど, SML#コンパイラがデフォルトで リンクするライブラリは-lで指定しなくても利用できる.

28.8.2 プログラムのコンパイル

ファイルに書かれたSML#プログラムをコンパイルする場合, もしただひとつの.smlファイル(および対応する.smiファイル)のみ から成るプログラムならば,その.smlファイルをただ指定するだけで実行 形式ファイルを得ることができる.

    $ smlsharp foo.sml

実行形式ファイルの名前をa.outから変えたいときは-oオプ ションを指定する.

    $ smlsharp -o foo foo.sml

28.8.3 分割コンパイルとリンク

複数のファイルから成るSML#プログラムを手でコンパイルして リンクするときの標準的な手順は以下の通りである.

    $ smlsharp -c -O2 foo.sml
    $ smlsharp -c -O2 bar.sml
    $ smlsharp -c -O2 baz.sml
    $ smlsharp foo.smi

まず,SML#プログラムを構成する各.smlファイルを -cを付けたsmlsharpコマンドでそれぞれ独立かつ順不同に コンパイルする. foo.smlのコンパイルに成功すると, オブジェクトファイルfoo.oが生成される. 全ての.smlファイルのコンパイルが完了した後, プログラム全体のエントリとなるコードを持つ.smlファイルのインターフェース ファイル(ここではfoo.smi)をsmlsharpコマンドに指定し, プログラム全体をリンクする. このときsmlsharpコマンドは,foo.smiから_require宣言 で辿れる.smiファイルを全て列挙し,拡張子を.oに変え,リンク対象の オブジェクトファイルのリストを得る.

ソースツリーの管理の都合などにより.smiファイルから.oファ イルへの対応を制御したい場合は,以下の例のように, ファイル名の対応表を持つファイルを作り-filemapオプションで指定する.

    $ smlsharp -c -O2 -o obj/foo.o foo.sml
    $ smlsharp -c -O2 -o obj/bar.o bar.sml
    $ smlsharp -c -O2 -o obj/baz.o baz.sml
    $ smlsharp -filemap=objmap foo.smi

このとき,objmapの内容は以下の通りである.

    = foo.o obj/foo.o
    = bar.o obj/bar.o
    = baz.o obj/baz.o

SML#プログラムは任意のC/C++プログラムやライブラリとリンクする ことができる. SML#プログラムをC/C++ライブラリとリンクする場合は, リンク時のsmlsharpコマンドラインにリンクするC/C++のオブジェクト ファイルやライブラリファイルを列挙する. 例えば,独自のCプログラムutil.cとOpenGLを利用するSML#プ ログラムfoo.smlをコンパイル・リンクする場合は以下のようにする.

    $ smlsharp -c -O2 foo.sml
    $ cc -c -O2 util.c
    $ smlsharp foo.smi util.o -lgl -lglu

28.8.4 Makefileの生成

分割コンパイルを使いこなすには, コンパイルとリンクを自動化する“make”コマンドと組み合わせると良い. makeコマンドを使うためには,ファイル間の依存関係が書かれた Makefileを作る必要がある. smlsharp -Mmコマンドを使うことで, SML#プログラムをmakeでビルドするために必要な完全なMakefileを 自動的に作ることができる.

例えば,3つの.smiファイル foo.smibar.smi,および baz.smi(とそれらに対応する.smlファイル) からなるプロジェクトがあるとする. これらの間には以下の_require関係がある.

  • foo.smibar.smi_requireしている.

  • bar.smibaz.smi_requireしている.

このとき,

    $ smlsharp -MMm foo.smi -o Makefile

は以下のMakefileを生成する.

SMLSHARP = smlsharp
SMLFLAGS = -O2
LIBS =
all: foo
foo: foo.o bar.o baz.o foo.smi
        $(SMLSHARP) $(LDFLAGS) -o $@ foo.smi $(LIBS)
foo.o: foo.sml foo.smi bar.smi baz.smi
        $(SMLSHARP) $(SMLFLAGS) -o $@ -c u.sml
bar.o: bar.sml bar.smi baz.smi
        $(SMLSHARP) $(SMLFLAGS) -o $@ -c u.sml
baz.o: baz.sml baz.smi
        $(SMLSHARP) $(SMLFLAGS) -o $@ -c u.sml

あとはただmakeを実行するだけでビルドが完了する.

  % make
  smlsharp  -o foo.o -c foo.sml
  smlsharp  -o bar.o -c bar.sml
  smlsharp  -o baz.o -c baz.sml
  smlsharp  -o foo foo.smi

プログラムを変更して _require関係が変化したならば,その都度 smlsharp -MMmコマンドでMakefileを生成し直す必要がある.

もしあなたのプロジェクトにml-lexやml-yaccなどのソースファイルが 含まれているならば,smlsharp -MMmだけでは十分ではない. それらのツールを起動して.smlファイルを生成するルールを 追加する必要がある. 例えば,構文解析器parser.grmを含むならば, smlsharp -Mmが生成したMakefileに対して, 以下のような parser.grm.smlを生成するための規則を手で追加する必要がある.

parser.grm.sml parser.grm.sig: parser.grm
        ml-yacc parser.grm
parser.grm.sig: parser.grm.sml

smlsharp -MMmが生成するMakefileと,これら追加のルールが 書かれたMakefileを分けておくと便利であろう. そのためのひとつの方法は, Makefileには追加のルールと自動生成ファイルのincludeを書くことである. 例えば,Makefileに以下のように書く.

# all
all:

# 
depend.mk:
        smlsharp -Mm foo.smi -o depend.mk
include depend.mk

# 
parser.grm.sml parser.grm.sig: parser.grm
        ml-yacc parser.grm
parser.grm.sig: parser.grm.sml

もちろん,あなたのお気に入りのMakefileテクニックを駆使してもよい.