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