Ocamllsp reporting "unbound module ..." when inspecting Base/Core file, with working dune build

I have a standard (I hope…) Ocaml installation in VSCode (on mac), and I’m able to get auto-formatting, jump to definition and other similar features to work. I’m also able to build my dune project.

I’ve read in many places that once you get a dune build running, ocamllsp should happily rely on it (and I assumed use the dune configuration) to find the right modules, and it seems to be happening partially (as in, I don’t seem to get duplicated dune/ocamllsp error when the build is running).

Starting from a continuously build (dune build @all --watch), if I comment out some dependencies, I immediately get a ‘dune’ error in VSCode (but not a ocamllsp-tagged one).

But even with a dune build succeeding, if I jump to the definition of ‘is_empty’ (i.e. in base/list.ml), ocamllsp gives me many ‘unbound module …’ errors (e.g. unbound module Import, even though it’s in the same directory).

How do I get ocamllsp to not complain about unbound modules when looking at files like base/list.ml ?

AFAIR, intellisense for files outside the project is not supported.

1 Like

This is one of the noted use cases for opam-monorepo: faq (opam-monorepo.faq)

Using Merlin to navigate the project (there’s no distinction between jumping to a definition in the project’s code or in its dependencies)

1 Like

Thanks for pointing me out to opam-monorepo!

I tried to set it up, sadly it doesn’t look like it’s pulling any dependencies.

I can see ‘ocaml’ as a dependency in my .opam and .opam.locked files, so I was (naively?) expecting the ocaml libraries to be pulled (on opam monorepo pull) into a duniverse directory (so that they are now part of the project and seen by IntelliSense). Sadly it seems no duniverse directory is created on pull!

% opam monorepo lock
==> Using 1 locally scanned package as the target.
[WARNING] Unknown variable "ocaml-system:version"
[WARNING] Unknown variable "ocaml-base-compiler:version"
[WARNING] Unknown variable "ocaml-variants:version"
==> Found 8 opam dependencies for the target package.
==> Querying opam database for their metadata and Dune compatibility.
==> Calculating exact pins for each of them.
==> Wrote lockfile with 0 entries to /Users/<user>/dev/foo/foo.opam.locked. You can now run opam monorepo pull to fetch their sources.

% cat foo.opam.locked
opam-version: "2.0"
synopsis: "opam-monorepo generated lockfile"
maintainer: "opam-monorepo"
depends: [
  "base-bigarray" {= "base"}
  "base-threads" {= "base"}
  "base-unix" {= "base"}
  "dune" {= "3.6.1"}
  "ocaml" {= "4.14.0"}
  "ocaml-base-compiler" {= "4.14.0"}
  "ocaml-config" {= "2"}
  "ocaml-options-vanilla" {= "1"}

x-opam-monorepo-root-packages: ["foo"]
x-opam-monorepo-version: "0.3"

% opam monorepo pull
==> Using lockfile /Users/<user>/dev/foo/foo.opam.locked
==> No dependencies to pull, there's nothing to be done here!

I’m not sure why there are 0 entries considered.
Any idea what I may be missing there? It’s a pretty trivial dune project, just a small toy file.

Edit: the documentation says:

By default all dependencies outside of dune , ocaml and a few other base packages are treated as if they were to be incorporated in the duniverse.

but I haven’t found how to force such packages (e.g. ocaml) to be incorporated in the duniverse yet.

Note: by adding an explicit dependency on ‘async’, opam monorepo lock and opam monorepo pull are now pulling ~79 libraries into the duniverse directory, and that allows me to get IntelliSense working in VSCode (i.e. jumping to Core code that is in the duniverse).

Explicitly adding core as a dependency (before ocaml) in my dune-project file also seems to be installing core files in the duniverse.

I suspect my confusion came from the fact that I didn’t need to explicitly add core or base as dependencies in dune-project for dune to build properly. I suppose these are automatically found through the ocaml dependency. But somehow ocaml is ignored by ocam-monorepo (treated specially), and wasn’t getting pulled. It seems adding the dependencies explicitly is required.

1 Like

opam-monorepo co-author here:

opam-monorepo only pulls in dependencies that people would want to vendor. As such it assumes both OCaml and Dune are available (be it from an OPAM switch or e.g. distribution packages).

However, if you depend on Core, then you’d need to state so in your projects opam file (this is a good thing to do anyway and doesn’t have much to do with opam-monorepo, as you need to state your dependencies somewhere, otherwise it will be difficult for people to use your project - you can also generate it via dune by adding them in dune-project, here’s an example of how opam-monorepo does it), in such case opam-monorepo will find it and include it in the duniverse/ folder.

Edit: You can’t force ocaml to be part of the duniverse, because everything in the duniverse/ needs to be buildable with Dune, which is not the case for the compiler as far as I remember.

Thanks for the explanation. I think I got confused by the fact that it seemed like I originally didn’t need to explicitly add core as dependency (in the dune-project), with things still compiling!

That’s entirely accurate: you don’t actually need to have things declared in your opam or dune-project, you just need to have it installed in your switch (and declare it in your dune files). You probably have installed core before with opam install core or a similar command.

Having it in your .opam or dune-project files is just used for installing/distributing projects (and opam-monorepo), not for building.

I know, it is a bit confusing, we’re trying to reduce the amount of duplication and moving parts so in the future there will be one place to deal with dependencies, hopefully.