Ocamldebug: Transitively loading modules with load_printer


#1

Context: OCaml version 4.03

When trying to load_printer in ocamldebug, any dependencies of the module I’m trying to load are not automatically loaded. If module Foo does an open Bar, my session looks as follows:

(ocd) load_printer "foo.cmo"
Error during code loading: error while linking project/path/foo.cmo.
Reference to undefined global `Bar'

but if I explicitly load Bar first, it does manage to load Foo. From a concrete example (going down the stack of modules until reaching Core's Poly;

(ocd) load_printer "poly.cmo"
Error during code loading: error while linking my_project/src/third-party/core/core/bc/poly.cmo.
Reference to undefined global `Polymorphic_compare'
(ocd) load_printer "polymorphic_compare.cmo"
File my_project/src/third-party/core/core/bc/polymorphic_compare.cmo loaded
(ocd) load_printer "poly.cmo"
File my_project/src/third-party/core/core/bc/poly.cmo loaded

See? After I successfully load polymorphic_compare.cmo, I can load poly.cmo. This would be just a minor annoyance if my project didn’t also depend on, for example, str.cmo, which doesn’t live in the include paths of my project.

Weirdly, when I have printers_dep.ml:

type printer_test = PrinterTest of string

and printers.ml:

open Printers_dep
let foo : printer_test = PrinterTest "foo"
let bar : printer_test = PrinterTest "bar"
let pp_printer_test (PrinterTest s) = Format.print "<<%s>>" s

and compile and load my project with it, I can transitively load printers_dep.cmo;

(ocd) load_printer "printers.cmo"
File my_project/src/bc/printers.cmo loaded
(ocd) install_printer Printers.pp_printer_test
(ocd) p Printers.foo
Printers.foo: Printers.printer_test = <<foo>>

everything works how I would expect it to work.

Is there any reason why the modules I want to load fail to load, based on their dependencies? Is there a way around this or at least a way to find out in more detail what’s going on?


Alternatives to ocamldebug?
#2

ocamldebug does not transitively load modules. This is annoying but you can live with that.

Here is the infrastructure I recommend to use the debugger (that I stole for the Coq project and you can see in place at https://github.com/Kappa-Dev/KaSim/tree/master/dev)

  • build a library (a .cma) with all the modules from your project your custom printers will need. (This is done by writing down an db_printers.mllib file if you’re using ocamlbuild but ocamlbuild is so 2016 that you should do the equivalent jbuilder incantation)
  • if your project is spread over several directories or if your printers somehow depends upon external libraries, write shell script that is simply a wrapper for ocamldebug so that it is invoked with the required -I option (As far as I know, there is sadly no ocamlfind ocamldebug that would allow you to do -pkg something but that’s fine)
  • Write a file (that I call db still copying Coq) in which you write all the relevant load_printer "something.cma" and install_printer Foo.print_bar
  • You’re all set! Instead of launching the debugger directly, load your wrapper, before doing everything else in it, load your script and enjoy… In my case, it becomes:
KaSim pirbo$ dev/ocamldebug KaSim --version
	OCaml Debugger version 4.05.0

(ocd) source dev/db
File /Users/pirbo/.opam/4.05.0+flambda/lib/ocaml/str.cma loaded
File /Users/pirbo/.opam/4.05.0+flambda/lib/easy-format/easy_format.cma loaded
File /Users/pirbo/.opam/4.05.0+flambda/lib/biniou/biniou.cma loaded
File /Users/pirbo/.opam/4.05.0+flambda/lib/yojson/yojson.cma loaded
File /Users/pirbo/KaSim/bin/../_build/KappaLib.cma loaded
File /Users/pirbo/KaSim/bin/../_build/dev/db_printers.cma loaded
(ocd) r            
Loading program... done.
Kappa Simulator: DomainBased-3457-g3aecc939c-dirty
Time: 6764
Program exit.
(ocd) 

#3

OK now that I read the man page of ocamldebug (maybe for the first time :slight_smile: ), there is even better: rename the file that I called db in my explanation .ocamldebug and put it at the root of your project tree. It will be loaded automatically at startup by ocamldebug allowing you to skip the source db incantation!

You can be tempted to go for the ultimate and also include in this file some directory ./_build commands in order to avoid the need for shell wrapper for ocamldebug but I’m not sure how to do that when you need to locate external libraries…


#4

The last version is also what i ended up doing – but now my .ocamldebug contains a lot of subdirectories of ~/.opam//lib/ as search paths for the external printers, which i had to manually dig out by trial and error.

It’s a bit sad that ocamldebug is not more comfortable to use. When i debug something i would appreciate a tool that tries to assist me as much as possible. I think an ocamlfind-enabled version of the debugger would be a good addition. Also, colored output from the debugger could help readability.


#5

This sounds workable. It’s should also be doable to just do the dependency analysis in my build system and let it produce a file like that. I share n4323’s concern about the heavy ~/.opam dependencies, though.

I’ll give it a go, anyway. Thanks!