dune-ocaml : No implementations provided for the following modules:

918 Views Asked by At

I tried to compile an OCaml code with Dune but got the following error:

Error: No implementations provided for the following modules:
CallccBp referenced from bin/.CallccTest.eobjs/native/dune__exe__CallccTest.cmx

by executing the command : $ dune build

My project hierarchy is as follows:

callcc/

    bin/

      callccTest.ml

      dune
        [

         (executable

         (name callccTest)

         (libraries CallccBp))

        ]
   lib/
      CallccBp.mli

      dune
       [

       (library

       (name CallccBp)

       (modules_without_implementation CallccBp))
        ]

   test/

    callccTest.ml

     dune [
      (test
       (name callccTest))
       ]

callcc.opam

dune-project

How can I solve this problem?

2

There are 2 best solutions below

4
On BEST ANSWER

Looking at the discussion you had with octachron, let's start from the basics:

my_module.mli

File where you declare the signatures of your values, modules etc. Not mandatory, I'd advise not using them if you start with OCaml

my_module.ml

File where you implement your values, modules etc. Mandatory since these are the files that make your program run

Let's see this with a toy project:

.
├── bin
│   ├── dune
         (executable
          (name main)
         )
│   └── main.ml
├── dune-project
├── lib
│   ├── dune
         (library
          (name my_module)
         )
│   └── my_module.ml
└── program.opam

If I want to use values from my_module in bin/main.ml, I have to:

  • have values in my_module.ml
  • add the (libraries my_module) stanza in my bin/dune file
  • use these values with My_module.<name_of_value>

So this looks like:

.
├── bin
│   ├── dune
         (executable
          (name main)
          (libraries my_module)
         )
│   └── main.ml
         let () =
           let b = My_module.incr 3 in
           Printf.printf "%d\n" b
├── dune-project
├── lib
│   ├── dune
│   └── my_module.ml
         let incr a = a + 1
└── program.opam

Now, let's go back to your hierarchy:

callcc/
    bin/
      callccTest.ml
      dune
        [
         (executable
         (name callccTest)
         (libraries CallccBp))
        ]
   lib/
      CallccBp.mli
      dune
       [
       (library
       (name CallccBp)
       (modules_without_implementation CallccBp))
        ]
   test/
    callccTest.ml
     dune [
      (test
       (name callccTest))
       ]
callcc.opam
dune-project

Everything looks fine except from the fact that CallccBp.mli is just an interface, not an implementation. As a starter you could remove this file, create CallccBp.ml filled with these two functions:

CallccBp.ml

let callcc = failwith "TODO"
let throw = failwith "TODO"

If you compile, dune should not complain and now all you'll have to do will be to provide a much useful implementation than failwith "TODO"


And if we go back to our toy project, to see why you'd want to have an mli file:

.
├── bin
│   ├── dune
         (executable
          (name main)
          (libraries my_module)
         )
│   └── main.ml
         let () =
           let b = My_module.incr 3 in
           Printf.printf "%d\n" b
├── dune-project
├── lib
│   ├── dune
│   └── my_module.ml
         let dummy _ = failwith "USELESS"
         let incr a = a + 1
│   └── my_module.mli
         val incr : int -> int
         (** [incr d] will return [d] incremented by 1. Highly efficient. Trust me. *)
└── program.opam

I'll be able to use My_module.incr in bin/main.ml but not My_module.dummy because it is not shown by the mli file and thus not accessible outside of my_module.ml. And as a bonus, my_module.mli file is the entry point for a library user who doesn't want to know how it is implemented but just wants to use it knowing the available values, their types and, often, what they do from the comment.


The modules_without_implementation stanza is for mli files that don't need implementations, namely, type declarations files so modules looking like this:

AST.mli

type ('a, 'b) res = Ok of 'a | Error of 'b
type num = Int of int | Float of float
type person = {id : int; name : string; age : num}

And you can use them in another file like this:

file.ml

type t = {player1 : AST.person; player2 : AST.person}

let whos_older p1 p2 =
  Printf.printf "%s is older\n"
    (if p1.AST.age > p2.AST.age then p1.name else p2.name)

But that's not really useful when starting since, once again, I'd advise not touching mli files in the beginning

8
On

The error message is complaining that there is no implementation (aka no ml file) for the module CallccBp. Without knowing the content of CallccBp, it is probable that this module contain either an exception or an extension constructor declaration (or any other kind of runtime components). Your first fix should be to add a callccBp.ml file and remove the (module_without_implementation ...) line.