I am new to the OCaml and I'm confused with the file of .cma, .cmo and .cmx. Sometimes I have to include a .cma file in the compile command but sometimes I have to include a .cmo file.
Why is there a such difference for library? Is it the same concept in C++ as library and include path?
Example: ocamlc -o executable str.cma extstring.cmo mycode.ml
Thanks
You may think that .cmo
is library, but it's not.
.cmo
is bytecode object file. It's like .class
in Java..cma
is bytecode library. It's produce by archiving some .cmo
into .cma
.cmx
is produced by ocamlopt
(the native-code compiler). Main output files of ocamlopt
is .o
but ocamlopt
also produce it.To create executable files, we arrange .cmo
and .cma
like ocamlc -o executable lib.cma a.cmo b.cmo ...
to link them.
You can write .ml
here instead of .cmo
but it's the same as compiling .ml
with -c
and link the .cmo
and other files.
For your deep undestanding, it's better to check how each files (related to ocaml) are produced.
Let's see what files are produce by ocamlc
and ocamlopt
.
[/tmp/test] ls
test.ml
[/tmp/test] cat ./test.ml
let id x = x
[/tmp/test] ocamlc -c /tmp/test/test.ml
[/tmp/test] ls
test.cmi test.cmo test.ml
[/tmp/test]
Now I compiled test.ml
file and compile it with ocamlc
with -c
option
(the content of test.ml
is not matter here).
You see ocamlc
outputs two files:
test.cmi
: Compiled interface file. This file includes type information of functions, variables in test.ml
for separate compilation.test.cmo
: Bytecode object file: It's like .class
file in Java.We use .cmo
files to create executable files.
[/tmp/test] ocamlc -c test.ml
[/tmp/test] ocamlc -o a.out test.cmo
[/tmp/test] ls
a.out test.cmi test.cmo test.ml
You see a.out
file are produced via the .cmo
file.
.cma
are library files. These are produced by composing multiple .cmo
files.
[/tmp/test] ls
test.ml lib.ml
[/tmp/test] cat lib.ml
let i = Test.id 1
let j = Test.id 2
[/tmp/test] ocamlc -c test.ml; ocamlc -c lib.ml
[/tmp/test] ls
lib.cmi lib.cmo lib.ml test.cmi test.cmo test.ml
[/tmp/test] ocamlc -a -o testlib.cma ./test.cmo lib.cmo
[/tmp/test] ls
lib.cmi lib.cmo lib.ml test.cmi test.cmo test.ml testlib.cma
Now I create lib.ml
(which use id
function in test.ml
) and compile test.ml
and lib.ml
, then link them to create testlib.cma
(option -a
means creating a library).
You can see .cma
is just packed with .cmo
files.
To use the library, we just arrange it with other object files.
[/tmp/test] cat user.ml
let _ = print_int (Lib.i + Lib.j)
[/tmp/test] ocamlc -c user.ml
[/tmp/test] ocamlc -o a.out testlib.cma user.cmo
Finally, let's check what files are produce by ocamlopt
.
[/tmp/test] ocamlopt -c ./test.ml
[/tmp/test] ls
test.cmi test.cmx test.ml test.o
ocamlopt
produces
test.o
: Native object filetest.cmi
: Compiled interaface filetest.cmx
: Also native object file, but it is mainly used for inlining functions across files!!!So, the difference is here (when there's a x
in the file extension, it means it's a native-code compiled object so that it runs faster. The cmx
files are obtained with ocamlopt
and the cmo
files with ocamlc
) :
.cma
/ .cmxa
-> libraries that are already available for the programmer (standard libraries and libraries you installed).cmo
/ .cmx
-> object files corresponding to your .ml filesTL;DR : .cm(x)a
files were not created by you, .cm(o|x)
files were.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With