Kites
Kites

Reputation: 1168

Using ocamlc to compile libraries independently

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

Answers (2)

Virgile
Virgile

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

Jeffrey Scofield
Jeffrey Scofield

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

Related Questions