Running tests when using dune build watch-mode

ocaml-lsp recommends running dune build --watch-mode. Doing so prevents running tests as the build directory is locked by that dune process.

What is the recommended way of using dune and ocaml-lsp doing test driven development?

1 Like

You can use dune runtest --watch.

3 Likes

Starting utop with local libraries (dune utop <dir>) is still an issue when the build directory is locked by the previous dune process in watch mode.

1 Like

I too am having this issue. I’m new to Ocaml and trying it now by following cs3110 book. It’s the first time I encounter an LSP that works only when running build --watch on the current project. It’s really frustrating to have to stop the build before running utop, then start it again. Also because reloading a file in utop is discouraged, one has to constantly run and exit utop, thus requiring to constantly start and stop the build process.
This is so far not enough to discourage me from learning Ocaml, but it sure is not a good learning experience.

2 Likes

This cannot be universally true, often the LSP works for me, accurately highlighting current type errors and unused-binding warnings as I type, without a fresh build or a continuous rebuild. It eventually gets stale though (reminding me to fire up the dune build -w command).

An alternative to running dune in watch mode is to use entr to create an ad hoc builder/watcher.

Something like this:

find ./lib/ -name "*.ml" | entr -c bash -c 'dune build && echo OK'

This won’t lock any files, so you can reload your dune utop process more easily that way.

To me this is problematic. The expectation is that the LSP works always, not often.
If I’m learning and writing Ocaml, I want to focus on my program, not on why the LSP is not working, launching and killing build watch to be able to switch from LSP, to run test, to run utop.
There is a fundamental flaw in the design of the LSP.

1 Like

That’s some outside-of-the-box thinking. I’ll try it. Thank you!

Due to OCaml’s expressive module system, the LSP needs to rely on build artifacts for a whole-project build to get cross-module typing and code locations correctly. If it was the LSP’s responsibility to keep the artifacts up to date, it might lead to a mismatch vs. user expectations regarding build configuration at a particular moment (I imagine the LSP would use the default build configuration of the project).

PS. In my recent experience the LSP (Merlin-based VSCode OCaml Platform specifically) does not need an up-to-date build for within-module changes.

1 Like

So what is the message to people coming to OCaml and experience this completely broken workflow regarding dune and LSP?

the dune lock is a pain point for other workflows too, but it has been acknowledged by the dune team. So there’s hope so see a fix.

In the meantime, one can run dune build @@default @runtest --watch which would do what you want. It builds all the code and runs the tests according to changes in the filesystem.

6 Likes

Oh and there’s also a way to build the utop binary in parallel to all that. The downside is that it has to be launched by hand later on.

dune build .utop/utop.bc @@default @runtest --watch

The utop binary will be accessible at _build/default/.utop/utop.bc.

One could create an alias which depends on all this:

(rule
 (alias default)
 (deps
  (alias_rec all)
  (alias_rec runtest)
  .utop/utop.bc)
 (targets)
 (action
  (echo done)))

and then dune build -w does more or less everything

3 Likes