I sometimes insert #mod_use "foobar.ml" into .ocamlinit to debug my library on OCaml toplevel. When I use Dune, however, I noticed some auto-generated files (e.g. parser.ml generated by parser.mly by Menhir) are not recognized by dune utop. How to configure dune utop to be able to find these files? Should I build a custom toplevel using toplevel stanza?
$ cd lib
$ dune utop .
Entering directory '/path/to/foobar'
─┬─────────────────────────────────────────────────────────────┬─
│ Welcome to utop version 2.4.1 (using OCaml version 4.08.1)! │
└─────────────────────────────────────────────────────────────┘
Cannot find file parser.ml.
Cannot find file lexer.ml.
Type #utop_help for help about using utop.
─( 16:11:53 )─< command 0 >───────────────────────{ counter: 0 }─
utop # (* BTW Parser can be opened here *)
open Parser;;
─( 16:12:39 )─< command 1 >───────────────────────{ counter: 0 }─
utop #
I confirmed I can open Parser on dune utop, but values which should be defined in parser.ml such as Parser.A (a type constructor of a token) are not bound.
$ dune utop .
Entering directory '/path/to/foobar'
─┬─────────────────────────────────────────────────────────────┬──
│ Welcome to utop version 2.4.1 (using OCaml version 4.08.1)! │
└─────────────────────────────────────────────────────────────┘
Cannot find file parser.ml.
Cannot find file lexer.ml.
Type #utop_help for help about using utop.
─( 17:39:57 )─< command 0 >────────────────────────{ counter: 0 }─
utop # open Parser;;
─( 17:39:57 )─< command 1 >────────────────────────{ counter: 0 }─
utop # Parser.A;;
Line 1, characters 0-8:
Error: Unbound value Parser.A
Since the library foobar is wrapped, all modules are available as Foobar.ModuleName. Your parser is thus Foobar.Parser. The Parser module that you see at the toplevel is the compiler one (this is unfortunate implementation detail of dune utop).
Thank you for the explanation! I can open Foobar.Parser. I can also snip Foobar. if I write open Foobar into .ocamlinit. #mod_use is unnecessary.
Can I ask another related question? If I locate all above codes in one directory, then how to open Parser? Foobar module is not found on dune utop. Is it necessary to separate lib and bin?
Thank you for the information! It really helps me. I now fully understand why I can/cannot open modules in my real project.
But why does dune utop only handle libraries? I think it’s inconvenient, for example, when testing main.ml for executables in REPL. Is there any technical reasons? How about wrapping things defined in programs for executables by a module such as Main, like Dune does for libraries?
That’s exactly the idea. That’s also why we can’t have inline tests in executables. I’ve been wondering about allowing to specify executables by function names rather than module names. That would make such things possible.
I don’t understand why dune utop shouldn’t used for private codes; I think it’s used for testing internal/private codes by hands. “It is possibly effectful (more likely than libraries)” is a reason to understand a little more for me.
Anyway, thank you two for letting me know how to use generated files! It really helps me. I select octachron’s reply as a solution
To workaround this problem, at ahrefs we write the whole code of the executable in a library and only one module for the executable itself. It’s not ideal, but we survive.
If you load it in the utop, utop would print Hello, world! and exit immediatly because of the exit 0, so you wouldn’t be able to do anything. The entry point of OCaml program is always a toplevel expression, that’s why we can’t load binaries in the toplevel or define inline tests in executables.
The workaround @Khady mentioned is indeed the only solution at the moment. In the future, we are thinking of allowing to declare executables by function names rather than module names. i.e. instead of the entry point being a toplevel expression, it would be a function like this:
let main () =
print_endline "Hello, world!";
exit 0
Then in your dune file you would write something like this: