I’m trying to follow Oleg’s tutorials and papers on MetaOCaml and using the 5.3.0+BER switch. All I can find to help setup dune to use MetaOCaml is this Make dune works with metaocaml · Issue #1413 · ocaml/dune · GitHub which seems to have been around for some time. What is the current state of play? Is there somewhere I can find to help me get setup with dune - I am experiencing weird errors that mean nothing to me when I try and build any code:
File "_none_", line 1:
Warning 58 [no-cmx-file]: no cmx file was found in path for module Runcode, and its interface was not compiled with -opaque
File "_none_", line 1:
Error: No implementation provided for the following modules:
Dynlink referenced from Runnative (/Users/simon/.opam/5.3.0+BER/lib/ocaml/runnative.cmx)
Thanks in advance for any instructions on making this work. Please be aware I am not that familiar with the build tools so I’d need exact detail of what incantations to put in whatever files. I’ve so far only ever fiddled with dune-project and dune files.
Thanks now I make progress! I’m using the right module for native however this is more of something implementation specific thing I don’t understand as this program is exactly Oleg/Ershov’s example…
dune exec xxv 5.3.0+BER
Fatal error: exception Failure("The code built at File \"bin/main.ml\", line 15, characters 21-48 has hardly serializable CSPs: square at File \"bin/main.ml\", line 12, characters 47-53\n\nsquare at File \"bin/main.ml\", line 12, characters 47-53\n\nIt may be allowed in the future: do tell if you need it.")
let square x = x * x
let rec spower n x =
if n = 0 then [%metaocaml.bracket 1]
else if n mod 2 = 0 then [%metaocaml.bracket square [%metaocaml.escape spower (n/2) x]]
else [%metaocaml.bracket [%metaocaml.escape x] * [%metaocaml.escape spower (n-1) x]]
let spower7_code = .<fun x -> .~(spower 7 .<x>.)>.
open Runnative
let spower7 = run spower7_code
let () =
Printf.printf "%d" (spower7 7)
I may be missing the entire point here but shouldn’t that work?
You’ve encountered a limitation in the MetaOCaml implementation. The use of square within brackets is an instance of “cross-stage persistence”, because square is defined at one stage and used in a later stage. Cross-stage persistence of functions (closures) is not currently supported with native code compilation.
One workaround is to define square in a separate module, which will give it a globally-visible name, which can be saved in the generated code in place of the function value, and will work as expected with native code compilation.
Thanks for the explanation and the reference- I think I’d seen that limitation w.r.t. data; putting those symbols in another module makes perfect sense.
Spoke too soon: I factored out the square function into another module. Which I checked could be opened and used from my main.ml. So module is ok I even generated an interface to be sure… I could get the MetaOCaml to generate and run some code ok if I did not use the square function at all. Now using the square function from this other module results in the following:
simon@eta [xxv]> dune exec xxv 5.3.0+BER
File "/var/folders/q6/nff8jbj523s0cy2xz9rchh1r0000gn/T/runnadc6e8.ml", line 3, characters 43-59:
3 | (Xxv.Extra.square
^^^^^^^^^^^^^^^^
Error: Unbound module Xxv
Fatal error: exception Sys_error("/var/folders/q6/nff8jbj523s0cy2xz9rchh1r0000gn/T/runnadc6e8.cmi: No such file or directory")
Raised by primitive operation at Runnative.compile_source in file "runnative.ml", line 40, characters 12-22
Called from Stdlib__List.iter in file "list.ml", line 112, characters 12-15
Called from Runnative.compile_source in file "runnative.ml", line 40, characters 2-34
Called from Runnative.run_native in file "runnative.ml", line 84, characters 21-56
Called from Dune__exe__Main.spower7 in file "bin/main.ml", line 11, characters 14-30
simon@eta [xxv]> more /var/folders/q6/nff8jbj523s0cy2xz9rchh1r0000gn/T/runnadc6e8.ml 5.3.0+BER
Runnative.result__ := Some (Obj.repr (fun x_1 ->
x_1 *
(Xxv.Extra.square
(x_1 *
(Xxv.Extra.square (x_1 * 1))))))
Also tried putting the module in the bin directory the runtime compilation could not still not find the module. I guess that’s a wrap for me as I can make no further progress as is; maybe some paths need to be setup for the runtime compilation to succeed. I guess this would be a general problem for all JIT style module resolution. Maybe inlining? Anyway as far as I see it from a naive users point of view:
Runnative vs. Runcode - need to decide upfront (in the source) which runtime is targeted. (would need some macro to detect this e.g. when loading into utop?)
No tooling support for MetaOCaml syntax: seems ocamlformat, Merlin (at least) need updating
Outstanding issue with runtime compilation dependent on any user modules (seems ok for stdlib tho’)