Supporting both standard and multicore compilers in a dune project

I am developing a library which uses multicore. However to support users on Mac M1, I would like to provide a version of the library which can be compiled with a standard (non-multicore) compiler.

All the multicore-related code is contained in one single module. To optionally support a standard compiler, my idea was to use virtual libraries in dune to provide a single-core implementation of this module. Here is the first part of my dune file:

(library
  (name multicore_compute)
  (virtual_modules multicore_compute))

(library
  (name multicore_compute_real)
  (libraries domainslib)
  (implements multicore_compute))

I hope the implementation can be swapped with

(library
  (name multicore_compute_fake)
  (implements multicore_compute))

However, dune fails with the following error message:

make -k
dune build --profile release @install
Internal error, please report upstream including the contents of _build/log.
Description:
  ("dependency cycle that does not involve any files",
  { frames = [ ("<unnamed>", ()); ("<unnamed>", ()); ("<unnamed>", ()) ] })
Raised at Stdune__code_error.raise in file "src/stdune/code_error.ml", line
  9, characters 30-62
Called from Stdune__exn_with_backtrace.map in file
  "src/stdune/exn_with_backtrace.ml", line 20, characters 40-45
Called from Stdune__exn_with_backtrace.map_and_reraise in file
  "src/stdune/exn_with_backtrace.ml", line 22, characters 35-45
Called from Fiber.Execution_context.forward_exn_with_bt in file
  "src/fiber/fiber.ml", line 138, characters 10-17

I must not crash.  Uncertainty is the mind-killer. Exceptions are the
little-death that brings total obliteration.  I will fully express my cases. 
Execution will pass over me and through me.  And when it has gone past, I
will unwind the stack along its path.  Where the cases are handled there will
be nothing.  Only I will remain.
make: *** [Makefile:5: all] Error 1

I am unsure whether this is a bug in dune or if there is a problem with my dune file.

Also, if there are better ways of supporting different compilers, I would be happy to learn about these.

The dune-project file contains (lang dune 2.9)

Hi!
Regardless of whether you are trying to do is feasible with dune and virtual modules, this error message indicates a bug in dune. Can you file an issue here? thanks!

Sure, dependency cycle that does not involve any files · Issue #5447 · ocaml/dune · GitHub

I remember having the exact same error recently but IIRC it’s already fixed in the main branch. Did you try it ?

As far as I can see, there is still an error in the main branch. This is what I get

[pkl@zeta dependency_cycle.t]$ /tmp/dune/_build/default/bin/dune.exe build
File "dune", line 11, characters 0-70:
11 | (executable
12 |    (public_name hello_world)
13 |    (libraries multicore_compute))
Error: Some modules don't have an implementation.
You need to add the following field to this stanza:

  (modules_without_implementation multicore_compute)
Internal error, please report upstream including the contents of _build/log.
Description:
  ("internal dependency cycle", { frames = [ ("<unnamed>", ()) ] })
Raised at Memo.Exec.exec_dep_node.(fun) in file "src/memo/memo.ml", line
  1366, characters 31-64
Called from Fiber.Scheduler.exec in file "src/fiber/fiber.ml", line 854,
  characters 10-13
-> required by ("gen-rules", "default")
-> required by ("load-dir", In_build_dir "default")
-> required by ("build-alias", { dir = "default"; name = "default" })
-> required by ("toplevel", ())

I must not crash.  Uncertainty is the mind-killer. Exceptions are the
little-death that brings total obliteration.  I will fully express my cases. 
Execution will pass over me and through me.  And when it has gone past, I
will unwind the stack along its path.  Where the cases are handled there will
be nothing.  Only I will remain.

EDIT: The new branch produces a different error.

As an alternative mechanism, you might want to look at this dune file in @dinosaure’s library where the file monotonic_clock.ml is generated by an OCaml script to which dune passes the system’s name:

Thank you, that works.