OCaml プログラムをコンパイルする
インストールとか環境構築については今度書くとして、今日はコンパイルについて。
バイトコードとネイティブコード
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.opt
ocamlopt.opt
ネイティブコード にコンパイルされた バイトコード および ネイティブコード コンパイラ。 ネイティブコード コンパイルが可能な環境では通常このコンパイラを使う。
OCaml コンパイラソースで make opt の後に make opt.opt を行うと作成される。 通常の ocamlc, ocamlopt は バイトコード で実行されるが、 *.opt コンパイラはネイティブコードに コンパイルされているため ocamlc, ocamlopt よりコンパイル速度が早い。 (バイトコード版コンパイラがひどく遅いわけではないが。)
ocamlc, ocamlopt 以外の OCaml のツールにも、.opt の suffix がついた ネイティブコードバージョンが存在するのでそちらを使ったほうがよい。