OCaml コンパイルの続き
(last update: 2017/09/23)
前回の続き。
$ ocamlc -o fact10 fact.ml main.ml
コンパイラ ocamlc
や ocamlopt
に -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
で試した場合も同様の結果になった。