Some of the functions and modules I’m using in my native executable, are not able to compile to JS using js_of_ocaml. For example, Nocrypto cannot compile to JS, and some of the Core.Time functions are not in Core_kernel.Time. However, there are straightforward JS equivalents I could use.
How can I write these stubs so that the same library can compile both JS and native? For example, I have a library that could call either Nocrypto.Hash.SHA284.digest or a JS file called crypto.js with sha384_digest, depending on the compilation target. How would I set jbuilder up to compile that?
Related question: if I want a type that is one thing when doing our JS compilation (perhaps a JS object) and another thing (probably a Core.Time.t) for native compilation, how do I do that. I guess I want to create a MyTime.t that abstracts over those two types, but I don’t know where to get started with this.
I do not know if what you want to do can be achieved with js_of_ocaml but you might be interested in checking Bucklescript ( https://bucklescript.github.io/ ) which enables linking to JS functions as exernals. I do not know how it works with jbuilder though, it seems to have its own build system.
As for your second question, no idea, but there is, linked to Bucklescript again, bsb-native that enables compiling to ocaml instead of JS ( https://github.com/bsansouci/bsb-native ) I’d expect that you can give alternatives depending on the backend.
There is work-in progress to support that out of the box in jbuilder/dune, it’s called Library Variants. The idea is to define a commun signature for various implementations, depending on the backends you want to use. Tip: we are very interested to have this for MirageOS
That feature is not planned for dune 1.0, but you can already achieve something similar by tweaking a bit your build system: see https://github.com/diml/variants-workaround for a template. The trick is to compile the common mli with -no-keep-locs on 4.06.1 and to choose the right implementation at link time.
That’s great! We are in the process of chaning some of the mirage libraries to use that scheme too, to have both a portable OCaml and an efficient C implementation for checksums and hashes. We should add a JS backend too at one point too.
Using --keep-locs allows to get better error messages. It adds locations to the cmi files, which make them non relocatable. See https://github.com/ocaml/ocaml/pull/1219 for the rational of turning that on per default and the related discussion.
Note: I think it may be possible to get good error messages without using --keep-locs to compile .cmi files, but that would require work. The idea is to define a notion of “paths to a definition within an interface” (today we identify those definitions just by their source location, which is less abstract), and use these paths to query locations in a separate .cmti file. I am not fully sure that it would work, but it can be tried; we haven’t because it was argued that --keep-locs is a low-effort way to get the nice errors without much downsides. If people re-evaluatate the downsides, it could motivate pouring work into alternatives.