Crossing OCaml

How does link to link work in OCaml?

For example, suppose I have 3 modules declared as

  • A.ml
  • B.ml
  • C.ml

out of which

  • A requires B and C
  • B requires A

How do I get started compiling?

Since order matters with ocamlc or ocamlopt , how can I fix the cross-link between B and A ?

I try to compile them all in ocamlc -c first with ocamlc -c , and then combine all of them together, but without success, since the substitution variables will simply move the problem from the module to another.

Specific error:

Error: A.cmo binding error: Link to undefined global `B '

(or vice versa if I change the order of the arguments)

I think this is a simple question, but I can’t solve it .. thanks in advance

+6
module linker recursion ocaml cross-reference
source share
2 answers

You need to combine the modules into one file and make them recursive . I do not believe that there is a way to do this from the process of compiling two separate files.

 module rec A : sig val f : int -> int val g : int -> int end = struct let fx = (Bg x) + 1 let gx = x + 1 end and B : sig val f : int -> int val g : int -> int end = struct let fx = (Ag x) + 1 let gx = x + 1 end 

EDIT: From your comment, I assume that you have an analyzer type definition and functions that handle / work with the type in the same file. I agree with you, that makes sense. But, just like you, if this file not only worked on this type, but also called the parser to create the data, how is its constructor going to build it? My solution was to split this type into its own module and open this module in the module that performs the operations.

Therefore, you break A into ( A and A' ), where A' contains the type created by B and is used in A Your addictions become

  • A need A' and B and C
  • B requires A'

For example, I have a parser for configuration files that I use to run any application that I write.

 ConfType --contains the type t Conf --calls parser, and contains helper functions for type ConfType.t ConfParser --for ocamlyacc ConfLexer --for ocamllex 

An alternative to all this is the use of polymorphic options. This way you remove the dependency since they are defined by ad-hoc. Of course, the type generated by the parser may be different than the one found in Conf, and the compiler will not be able to help you with the error.

+7
source share

The Ocaml language supports recursion between modules, but the compiler does not support recursion between compilation units. Thus, you cannot A.ml need B.ml and B.ml needing A.ml Refactoring to remove recursion is best if you can do it easily, but suppose you cannot.

One solution explained by nlucaroni is to collect both modules into the same file and use module rec . Another solution sometimes is to turn one module into a functor, for example, turn A into a functor F , which takes an argument with signature B and first compiles a file that defines F , then B , then a file that just defines module A = F(B)

Ocamlyacc makes things more complicated, but you can fool it! You can write module A = functor (...) -> struct in the .mly header and the corresponding end in the footer. However, you will have to rewrite the generated .mli to add module A : functor (...) -> sig and end as part of the build process. (I know that I did this earlier in order to solve the same problem as yours, although I do not remember where I cannot give an example of real life.)

Another possibility worth exploring is to switch from Ocamlyacc to Menhir , which is a replacement for Ocamlyacc (with little to do with porting, because the syntax is the same) with some nice features that can help you, for example, support for parameterized parser modules ( i.e. functors).

+3
source share

All Articles