Compilation Pipeline
.ml implementation, .mli interface, .cmi compiled interface, .cmo/.cmx compiled object, .cma/.cmxa library archives, .cmt/.cmti typed trees (for tooling), .cmxs dynamic plugin.
41.1 Compilers
bytecode .cmo / .cma portable, fast compile, runs on ocamlrun native .cmx / .cmxa / .o wrapper resolving libraries
ocamlfind ocamlopt -package str -linkpkg used by build systems lexer generator (.mll) ocamlyacc / menhir parser generators (.mly)
41.2 File types
.ml implementation, .mli interface, .cmi compiled interface, .cmo/.cmx compiled object, .cma/.cmxa library archives, .cmt/.cmti typed trees (for tooling), .cmxs dynamic plugin.
41.3 Compiler pipeline
Inspect: ocamlopt -dparsetree -dtypedtree -dlambda -dcmm -S file.ml.
Source → Lexer → Parser → Parsetree (PPX operates here)
→ Typing → Typedtree → Lambda (untyped IR)
→ [bytecode] Instruct → bytecode
→ [native] Flambda (optional optimizer) / Closure → Cmm → Mach → Linear → assembly41.4 Flambda
An optimizing middle-end (inlining, specialization, unboxing): opam switch create 5.3.0+flambda (or ocaml-option-flambda), compile with -O3. Jane Street's Flambda 2 / OxCaml branch adds modes (local_, unique), unboxed types, and stack allocation — an experimental superset worth watching.
41.5 Lexing & parsing with ocamllex + Menhir
(* lexer.mll *)
{ open Parser }
rule token = parse
| [' ' '\t' '\n'] { token lexbuf }
| ['0'-'9']+ as n { INT (int_of_string n) }
| '+' { PLUS } | '*' { TIMES } | '(' { LPAREN } | ')' { RPAREN }
| eof { EOF }(* parser.mly *)
%token <int> INT
%token PLUS TIMES LPAREN RPAREN EOF
%left PLUS
%left TIMES
%start <int> main
%%
main: e = expr EOF { e }
expr:
| i = INT { i }
| LPAREN e = expr RPAREN { e }
| a = expr PLUS b = expr { a + b }
| a = expr TIMES b = expr { a * b }(ocamllex lexer)
(menhir (modules parser))let parse s = Parser.main Lexer.token (Lexing.from_string s)41.6 Dynamic loading
Dynlink.loadfile "plugin.cmxs" loads plugins at runtime.
41.7 Cross-compilation & targets
Native backends: x86-64, ARM64, RISC-V, POWER, s390x. JS via js_of_ocaml, WebAssembly via wasm_of_ocaml, unikernels via MirageOS.
🧪 Part III Exercises
Write a GADT-typed stack machine where push/add instructions are checked to never underflow.
Implement a typed key-value heterogeneous map using Type.Id or an existential GADT.
Use polymorphic variants to compose error types from two independent "libraries".
Write a generator using effect handlers that yields all permutations of a list.
Implement async/await with effects on top of the cooperative scheduler from §35.6.
Parallel merge sort with Domainslib; benchmark against List.sort for 1M elements.
Write a PPX [%env "VAR"] that inlines an environment variable at compile time.
Bind a small C function (e.g., getpid) with both raw stubs and ctypes.
Implement a JSON parser using your own parser combinators (§33.7).
Build an Eio HTTP-less chat server: clients connect via TCP and broadcast lines.