OCaml コンパイルの続き

(last update: 2017/09/23)

前回の続き。

$ ocamlc -o fact10 fact.ml main.ml

コンパイラ ocamlcocamlopt-o オプションで実行ファイル名を指定してソース・ファイル .ml を渡すと実行ファイルが出力される。また .cmo.cmi などのファイルも生成される。

で、これは恐らく手順をスキップしているというか、コンパイラがよしなにやってくれている。順をおって一手ずつ進めるとしたらこうなる。

まずソースファイル .ml だけの状態から

$ ls
. .. fact.ml main.ml

fact.mlコンパイルする。(-c オプションを指定すると実行ファイルを作らずコンパイルだけする)

$ ocamlc -c fact.ml

$ ls
. .. fact.cmi fact.cmo fact.ml main.ml

次に main.mlコンパイルする。

$ ocamlc -c main.ml

$ ls
. .. fact.cmi fact.cmo fact.ml main.cmi main.cmo main.ml

このように 1 つずつコンパイルする場合も main.ml から先にコンパイルしようとするとエラーになった。依存される側(参照される側)から先にコンパイルする必要がある。

File "main.ml", line 1, characters 5-9:
Error: Unbound module Fact

で、オブジェクトファイル .cmoコンパイラに渡して実行ファイルを出力する。

$ ocamlc -o fact10 fact.cmo main.cmo

$ ls
. .. fact.cmi fact.cmo fact.ml fact10 main.cmi main.cmo main.ml

$ ./fact10
3628800

ちなみに .cmo を渡す場合も依存関係を無視してはいけない。main.cmo を先にするとエラーになる。

$ ocamlc -o fact10 main.cmo fact.cmo
File "_none_", line 1:
Error: Required module `Fact' is unavailable

コンパイラは賢いから人間がソースファイルを渡して「実行ファイルを作って」とお願いしてもやってくれるけれど、ソースファイルからオブジェクトファイルを生成して、それを結合して実行ファイルを作成するというのが本来の手順なのだろう。

でも、同じ結果が得られるなら最初から実行ファイルを作成した方が早いだろうし -c オプションはいつ使うのかという疑問がわく。

それは恐らく、もっと大きくて複雑なソフトウェアを作る場合には全体をパーツごとに分解して作っていくので、そういうときには、

ある部分は既にコンパイル済みの状態(オブジェクトファイル)で、 一部分だけコンパイル(ソースファイル -> オブジェクトファイル)し直して、 既にあるオブジェクトファイルと組み合わせて実行ファイルを作成する

という使い方をしたりするので必要、というか必須なのだと思う。(想像)

(追記 2017/09/23)

上記ではバイトコードコンパイラ ocamlc での結果を書いたが、ネイティブコードコンパイラ ocamlopt で試した場合も同様の結果になった。

参照