ocamldune

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


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?


Solution

  • 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:

    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