Getting signature of caml program

I have a project using OCaml that successfully compiles by using the dune

However, I want to know the signature of some file. The “ocamlc -i file.ml” works for let’s say small files. However, if the file has some dependency as is the case in this project then the answer to the question “Ocamlc -i error:Unbound module, how to fix it?” mentions the cmi files as needed to be compiled.

That is fine as things go but how could is use dune (which has access to all the cmi files) in order to get this signature file? The dune documentation does to even has “signature” in its 80 page pdf files.

2 Likes

Just hazarding a guess, your ocamlc line might work better if you wrap it in the right ocamlfind invocation.

The way I understand it, @Mathieu_DS would like to ask Dune to compute an interface file from an ML file. Invoking ocamlc trough ocamlfind manually would leave it with the user to provide the packages that the ML file depends on whereas Dune would compute these and compile dependencies when necessary.

We’re aware that this is a current limitation in dune. The issue is that adding such a rule for every ocaml module has performance implications for those who aren’t using this feature.

Luckily, dune’s internals are undergoing some major changes which will eventually make it possible for such a feature without backwards compatibility issues. There’s no eta yet, but stay tuned. In the meantime, there’s a workaround using Merlin that’s well known.

If my ml file compiles and I want to add an mli, my DIY solution so far has been the following:

  1. opam install cmitomli
  2. locate the cmi file for Foo.ml, using for example find <PROJECT ROOT> -name '*Foo.cmi'
  3. run cmitomli to produce a valid Foo.mli
  4. edit the mli as desired

Note that cmitomli.ml is just this:

let version = "1.0.0"

let cmi_to_mli infile =
  let x = Cmi_format.read_cmi infile in
  let l = x.Cmi_format.cmi_sign in
  Printtyp.signature Format.std_formatter l;
  Format.print_flush ();
  print_newline ();
  flush stdout

let usage () =
  Printf.eprintf "\
cmitomli %s for ocaml %s
Usage: cmitomli <file.cmi>\n%!"
    version Sys.ocaml_version

let main () =
  match Sys.argv with
      [| _; ("-help" | "--help" | "-h") |] -> usage (); exit 0
    | [| _; x |] -> cmi_to_mli x
    | _ -> usage (); exit 1

let () = main ()
2 Likes