Hello all,
I’m trying to separate a program of mine into separate modules, and it seems I just don’t get how OCaml’s module system is working.
Here is a very simplified version of what I’m trying to do, starting with all in a single file bar.ml
:
external _foo: string -> int * int = "caml_foo"
type my_record_type = {
x: int;
y: int
}
let foo s = (let x, y = (_foo s) in { x=x; y=y });;
let
z = foo "hello, world!"
in
Printf.printf "z.x = %d - z.y = %d" z.x z.y;
print_endline ""
I also have a file foo_stubs.c
containing the implementation for the C function caml_foo
.
So if I compile everything with ocamlopt
it works: ocamlopt -o bar bar.ml foo_stubs.c
produces the bar
executable, which works as expected.
~
But now, I’d like to isolate the first part in a separate module. So after reading the manual’s part about how modules & the file system work together, here what I tried:
I created a file foo.ml
, with the following code:
external _foo: string -> int * int = "caml_foo"
type my_record_type = {
x: int;
y: int
}
let foo s = (let x, y = (_foo s) in { x=x; y=y })
I changed the contents of the file bar.ml
to:
open Foo;;
let
z = foo "hello, world!"
in
Printf.printf "z.x = %d - z.y = %d" z.x z.y;
print_endline ""
The contents of the file foo_stubs.c
is unchanged.
But now, when I try to compile everything together, it no more works:
> ocamlopt -o bar bar.ml foo.ml foo_stubs.c
File "foo_stubs.c", line 1:
Error: No implementations provided for the following modules:
Foo referenced from bar.cmx
The strange thing being, individual compilations do work: neither ocamlopt -c bar.ml
, nor ocamlopt -c foo.ml
, nor ocamlopt -c foo_stubs.c
produce any error, and the .o
files are generated. Even weirder, if I change something in bar.ml
that makes it incompatible with the contents of foo.ml
(e.g replacing one of the %d
with a %s
in the Printf.printf
line), I actually get an error message:
> ocamlopt -c bar.ml
File "bar.ml", line 7, characters 44-47:
Error: This expression has type int but an expression was expected of type
string
So the compiler does read the contents of foo.ml
; it just doesn’t seem to recognize it as a proper module.
~
I tried quite a few other things, such as creating a file foo.mli
with the contents:
type my_record_type = {
x: int;
y: int
}
val foo: string -> my_record_type
and with foo.ml
containing only:
external _foo: string -> int * int = "caml_foo"
let foo s = (let x, y = (_foo s) in { x=x; y=y })
But it’s even worse: now compiling foo.ml
won’t even work:
> ocamlopt -c foo.ml
File "foo.ml", line 3, characters 38-39:
Error: Unbound record field x
I also tried to put everything in a module
declaration in a single file foo.ml
with the sig
part being the contents of foo.mli
and the former contents of the foo.ml
file in the struct
part:
module Foo:
sig
type my_record_type = {
x: int;
y: int
}
val foo: string -> my_record_type
end
= struct
external _foo: string -> int * int = "caml_foo"
let foo s = (let x, y = (_foo s) in { x=x; y=y })
end
But I’m getting the same kind of error:
> ocamlopt -c foo.ml
File "foo.ml", line 13, characters 40-41:
Error: Unbound record field x
And now I’m stuck. I just can’t figure out how to make this work.
I’m obviously doing something wrong, but I can’t figure out what. Any hint to put me in the right direction?
Thanks!