1. Install
Using the opam, the OCaml package manager, you can easily install and manage OCaml and packages.
bash -c "sh <(curl -fsSL https://opam.ocaml.org/install.sh)"
Run opam init to set up environment. By default it just creates some files in ~/.opam directory.
1.1. Getting a different version of OCaml toolkit
First, use opam list ocaml or opam switch list-available command to list the available OCaml compiler.
The easiest way to upgrade OCaml toolkit is simply run the command: opam upgrade
opam switch can create and manage isolated OCaml environment, similar to virtualenv of Python. So if you want to update the version of OCaml toolkit, it is highly recommended to create a new switch.
opam switch create ocaml.5.2.0
# If you want to create a named environment,
#opam switch create my-env ocaml.5.2.0
2. Writing code and run it
This is a sample program; Takes input from standard input, prints 1 if the input is leap year.
(* leap_year.ml *)
let is_leap_year year =
if year mod 400 == 0 then 1
else if (year mod 100 != 0) && (year mod 4 == 0) then 1
else 0
in read_int () |> is_leap_year |> print_int
We can simply run ocaml CLI tool to run it.
$ ocaml leap_year.ml
2022
0
$ ocaml leap_year.ml
2024
1
$
2.1. OCaml Bytecode
If you use ocamlc command, you can get bytecode from the original OCaml code.
$ ocamlc leap_year.ml
It will generate three files: .cmi, .cmo, and a.out file.
.cmi file is an inteface file. It does not contain the bytecode itself, but it has type information and module signatures.
.cmo file is an object file.
a.out file contains the actual compiled bytecode. ./a.out command to run the compiled bytecode. If you see the top of the content of compiled file, you might see the file starts with shebang(#!).
$ head a.out
#!/home/ch1keen/.opam/5.0.0/bin/ocamlrun
...
2.2. OCaml Native Executable
ocamlopt command will create a native executable from the OCaml source code.
ocamlopt leap_year.ml
Append -o option to specify the name of output. It is similar to gcc etc.
2.3. OCaml Native Executable (statically linking)
-
Pass the
-cclib -staticoption to theocamlopt.It will say
dlopen()function$ ocamlopt -cclib -static fib.ml -o fib /usr/bin/ld: /home/ch1keen/.opam/default/lib/ocaml/libasmrun.a(unix.n.o): in function `caml_dlopen': /home/ch1keen/.opam/default/.opam-switch/build/ocaml-base-compiler.5.0.0/runtime/unix.c:280: warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking $ -
Use musl libc instead of glibc.
$ file fib
fib: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=65eb04ad6f8610ff845b5d270bbd8b75eff738fd, for GNU/Linux 3.2.0, with debug_info, not stripped
References:
2.4. Create .cmm script from ocamlopt
Append -dcmm option to generate .cmm file. It might help you debugging the program.
let rec fib(n: int) = match n with | 0 -> 0 | 1 -> 1 | _ -> fib(n-1) + fib(n-2)
cmm:
(data)
(data int 3063 "camlFib__1": addr "camlFib__fib_268" int 72057594037927941)
(data int 1792 global "camlFib" "camlFib": int 1)
(data global "camlFib__gc_roots" "camlFib__gc_roots": addr "camlFib" int 0)
(function{fib.ml:1,11-87} camlFib__fib_268 (n/269: val)
(if (!= n/269 1)
(if (!= n/269 3)
(+
(+ (app{fib.ml:5,9-17} "camlFib__fib_268" (+ n/269 -2) val)
(app{fib.ml:5,20-28} "camlFib__fib_268" (+ n/269 -4) val))
-1)
3)
1))
(function camlFib__entry ()
(let clos/272 "camlFib__1"
(extcall "caml_initialize" "camlFib" clos/272 ->unit))
1)
When you look the script closely, it is a pseudo code that looks like the scheme language.
3. OCaml as a transcompiler
There are lots of OCaml to JavaScript transpiler.
-
Melange, an industrial ready program that compiles OCaml code to JavaScript.
-
js_of_ocaml that transpile OCaml bytecode to JavaScript.
6. See Also
-
Very long ago (around 2010) the Rust compiler was written in OCaml.
-
OCaml supports OCaml-oriented parser and lexer, which is called ocamllex and ocamlyacc.
-
OCaml Bindings to LLVM
-
Homepage: http://llvm.moe/
-