Reputation: 1168
I have three files:
$ ls
lib.ml desk.ml test.ml
$ cat lib.ml
let myfunction () = print_endline "Hello world"
$ cat desk.ml
module Liberty = Lib
$ cat test.ml
Desk.Liberty.myfunction ()
I want to compile a desk.cma
that does not expose the module Lib
, but is able to make use of it. For example, I've tried:
$ ocamlc -a lib.ml -o lib.cma
$ ocamlc -a lib.cma desk.ml -o desk.cma
$ ocamlc desk.cma test.ml -o test.byte
Unfortunately, if you change test.ml
to be Lib.myfunction ()
, the same compilation steps work just fine. I want it so that Lib
is not exposed to test.ml
and only exposed to desk.ml
. Does anyone know how to do this? Thanks very much!
Upvotes: 0
Views: 105
Reputation: 10148
It looks like you're looking for the -pack
mechanism of OCaml. This allows you to create a pack.cmo
(or pack.cmx
for native compilation) from several compilation units, like a pack.cma
library, but with the added advantage that you can have a corresponding pack.mli
interface with which you can hide the parts that should be internal to your pack
. In your example, you could for instance have:
-- lib.ml --
let myfunction () = print_endline "Hello world"
-- liberty.ml --
include Lib
-- desk.mli --
(* No module Lib: Lib will not be seen outside of the pack. *)
module Liberty: sig
val myfunction: unit -> unit
end
Then you can compile that with
ocamlc -for-pack Desk -c lib.ml
ocamlc -for-pack Desk -c liberty.ml
ocamlc desk.mli
ocamlc -pack -o desk.cmo lib.cmo liberty.cmo
This will give you a module Desk
, that contains only Liberty
a sub-module. Of course, desk.mli
can be used to get more fine-grained restriction, e.g. with
module Lib: sig end
module Liberty: sig val myfunction: unit -> unit end
you export Lib
with an empty signature, thus hiding a single (albeit the only one in the example ;-P) function from Lib
.
Upvotes: 2
Reputation: 66818
You're asking that Lib
be a module of desk.cma
that Desk
can use, but no other modules. I'm pretty sure the structure of a cma file doesn't offer this kind of control.
If you define Lib
inside Desk
you can make it a hidden detail.
$ ls
desk.ml desk.mli test1.ml test2.ml test3.ml
$ cat desk.ml
module Lib = struct
let myfunction () = print_endline "Hello world"
end
module Liberty = Lib
$ cat desk.mli
module Liberty : sig
val myfunction : unit -> unit
end
$ cat test1.ml
Desk.Liberty.myfunction ()
$ cat test2.ml
Lib.myfunction ()
$ cat test3.ml
Desk.Lib.myfunction ()
The Liberty module is visible to the test programs, but the Lib module isn't:
$ ocamlc -c desk.mli
$ ocamlc -a desk.ml -o desk.cma
$ ocamlc desk.cma test1.ml -o test1.byte
$ ./test1.byte
Hello world
$ ocamlc desk.cma test2.ml -o test2.byte
File "test2.ml", line 1, characters 0-14:
Error: Unbound module Lib
$ ocamlc desk.cma test3.ml -o test3.byte
File "test3.ml", line 1, characters 0-19:
Error: Unbound module Desk.Lib
You can implement Lib in a separate file, then include
it into the definition of the Desk.Lib
module.
I suspect this isn't a fully satisfying answer, but I hope it's helpful.
Upvotes: 0