インストールとか環境構築については今度書くとして、今日はコンパイルについて。
バイトコードとネイティブコード
OCaml をインストールすると標準で 2 種類のコンパイラがついてくる。
バイトコード
- コンパイルしたプログラムは機種(ハードウェア・OS)に非依存
- Linux でコンパイルしたものを Windows で実行したり、異なる環境でも実行可能
- 実行にはバイトコードインタプリタ
ocamlrunが必要(これも標準でついてくる)
ネイティブコード
- コンパイルしたプログラムは機種(ハードウェア・OS)に依存する
- コンパイルした環境と異なる環境では動かない場合がある
- インタプリタは不要でハードウェアから直接実行できる
- ネイティブコードの方が実行速度は速い
コンパイルしてみる
サンプルとして階乗を求める関数 fact と、
(* fact.ml *) let rec fact n = if n = 0 then 1 else n * fact (n - 1)
それに引数 10 を渡して実行した結果を表示するプログラムを書く。
(* main.ml *) open Fact let () = print_int (fact 10); print_newline()
ocamlc でコンパイル
コンパイルして実行ファイルを作成するには以下のように入力する。-o オプションで実行ファイルの名前を指定する。
$ ocamlc -o fact10 fact.ml main.ml
コンパイルすると実行ファイル fact10 と fact.cmi, fact.cmo, main.cmi, main.cmo というファイルが生成され、fact10 を実行すると結果が表示される。
$ ./fact10
3628800
しかし、ocamlc に渡す順番を逆にするとエラーになる。
$ ocamlc -o fact10 main.ml fact.ml File "main.ml", line 1, characters 5-9: Error: Unbound module Fact
これは main.ml の中で fact.ml で定義されている関数 fact を参照している、つまり main.ml は fact.ml に依存しているからである。
ocamlopt でコンパイル
ocamlc と同様に -o で出力するファイル名を指定する。
$ ocamlopt -o fact10 fact.ml main.ml
実行ファイルの他に生成されるファイルが ocamlc の場合とは一部異なった。
ocamlc では fact.ml から fact.cmi, fact.cmo が生成されたのに対して、fact.cmi は同じで、fact.cmo の代わりに fact.cmx と fact.o が生成されていた。
この *.cmi, *.cmo, *.cmx, *.o とやらは何だろうか。こういう普段見慣れないファイル形式が一度に複数出てくると、ウッてなるんだよね。落ち着いてマニュアルを見てみる。
.cmi とは
- インターフェイスをコンパイルしたもの
*.mliをコンパイルすると*.cmiが出力される*.mliが無い場合は*.mlから*.cmiが生成される
ocamlcでコンパイルした*.cmiとocamloptでコンパイルした*.cmiは同一
.cmo とは
.o とは
.cmx とは
参照
- OCamlプログラムをコンパイルする – OCaml
- Batch compilation (ocamlc)
- Native-code compilation (ocamlopt)
- 書籍『プログラミング in OCaml』

プログラミング in OCaml 〜関数型プログラミングの基礎からGUI構築まで〜
- 作者: 五十嵐淳
- 出版社/メーカー: 技術評論社
- 発売日: 2014/12/09
- メディア: Kindle版
- この商品を含むブログ (12件) を見る
ネイティブコードにコンパイルされたコンパイラ
上述の ocamlc と ocamlopt はバイトコードでコンパイルされたコンパイラのようで、ネイティブコードでコンパイルされたものもあり、通常はこちらを使うらしい。
ocamlc.optocamlopt.opt
ネイティブコード にコンパイルされた バイトコード および ネイティブコード コンパイラ。 ネイティブコード コンパイルが可能な環境では通常このコンパイラを使う。
OCaml コンパイラソースで make opt の後に make opt.opt を行うと作成される。 通常の ocamlc, ocamlopt は バイトコード で実行されるが、 *.opt コンパイラはネイティブコードに コンパイルされているため ocamlc, ocamlopt よりコンパイル速度が早い。 (バイトコード版コンパイラがひどく遅いわけではないが。)
ocamlc, ocamlopt 以外の OCaml のツールにも、.opt の suffix がついた ネイティブコードバージョンが存在するのでそちらを使ったほうがよい。