As far as I know, async cannot be used with MirageOS. Is there any work someone is doing to enable async to be used with a MirageOS unikernel?
Due to the fact that MirageOS is an operating system, usual syscalls and famous
libc functions are surely not available in MirageOS essentially. Indeed, into details, MirageOS (for the Solo5 target) uses a special caml runtime:
ocaml-freestanding which is an hacked version of OCaml with a static link to
nolibc (and few others libraries).
This is why we say: if your library depends (transitively or not) to the
Unix module, your project will not be (fully) available for MirageOS - and it’s why you can see some
*-unix variants of various MirageOS libraries.
async, or more precisely
core_kernel, they widely use some syscalls which are not available in MirageOS (such as
localtime for example). These projects are huge and it’s difficult for the MirageOS core team to try to remove properly these syscalls and maintain a smaller
async compatible with MirageOS on our own way.
In the opposite,
lwt did this split (between the scheduler and
Unix syscalls) at the beginning. You can find
lwt.unix. So, it was more easy to integrate
lwt in MirageOS and the time decided to strictly use
lwt as our scheduler - indeed, at some points, we abstracted the scheduler type
'a io but it was a bit a pain to maintain such abstraction (with a systematic specialisation to
'a Lwt.t) on all of our libraries.
So, of course, it should be possible to integrate
async_kernel into MirageOS - tweak a bit with
ocaml-freestanding to add some new syscalls or functorize
async over some specific syscalls (such as
Mirage_clock.S) and let
functoria about the application of these functors.
At the end, most of MirageOS projects are functorized over a scheduler. For example, you have a version of
async or some others libraries such as
decompress don’t depends on any syscalls (so they can be used with
lwt or … nothing!). This is on what we believe, be system-agnostic.
So about MirageOS itself, I don’t think that we have any plan to use
async - as I said, it’s a huge work. But the limit is mostly on the
async side than MirageOS according to our abstraction - and I don’t blame Janestreet , it’s fine and they may be don’t have the resource to do this job too! Indeed, we continuously think about
lwt as a spontaneous dependency due to its design but we keep in our mind that the community is larger than
lwt and the future will be about
Great writeup, @dinosaure!
Async_kernel is meant to convey the distinction between the parts of Async that depend on Unix and those that don’t. But, “does not depend on Unix” in this case means “works in js_of_ocaml and theoretically on Windows” but not “works in MirageOS”, so for example
You are right but evil are in the details!
Indeed, the problem comes with the
Unix dependency but more globally, anything with C stubs (like
core_kernel or the
Unix module) will have a problem with MirageOS.
As I explained, the first problem is the non-availability of some C functions (due to
nolibc). But the second problem is: how to compile a C stubs (like
otherlibs/unix/*.c or your own C stubs). Indeed, C stubs must be compiled with specific
*.h and, for Solo5, with specific flags.
MirageOS, or more specially
ocaml-freestanding and Solo5 put some
pkg-config files into your OPAM environment. By this way, some libraries such as
mirage-crypto can compile C stubs with specific flags. Currently, these flags are available with:
PKG_CONFIG_PATH := $(opam config var prefix)/lib/pkgconfig PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --cflags ocaml-freestanding
You can see a real example with
mirage tool does the right things about the link-step (to craft the operating system). Indeed, it will take these special artifact with
ocamlfind (unusable for a simple executable) with your operating system. By this way, we ensure a sanitized ELF object (between
ocaml-freestanding - the caml runtime and third-part libraries with C stubs such as
Such plumbing is a bit a pain and error-prone. So, in the case of
core_kernel, the second problem will be to ask JaneStreet to compile twice the
*.a of C stubs:
- one for an usual link with a simple host OCaml program
- the other to be able to link them with our special caml-runtime (
This is what we did for
bigstringaf which is a library outside the scope of the MirageOS eco-system but widely used by us. But, about
async, the problem will be more complex - the codebase is bigger and we talk about C so we can have some surprises!
Of course, at this point, you can say that such solution does not really scale and… you are true. Even if we want to limit as much as possible C stubs in our codebase, we reached several times some limitations (cross-compilation comes to my mind). This is an other big difference with
lwt, the core library does not have any C stubs!
However, the good news is (some teasing…): MirageOS 4! With the MirageOS core team, we currently work on a realistic solution about C stubs. I don’t want to go to details but the next release is through to fix these problem specially (with
So the first biggest issue (roadblock) with attempting to adapt Async to MirageOS is how the c stubs are handled by the MirageOS build system. After that the async stubs will need to be adapted to MirageOS?
So MirageOS 4 - with its dune integration - aims to solve the first issue?
Not exactly unfortunately, the first problem (about unavailable C functions) remains. However, MirageOS 4 should help to extend the set of MirageOS targets. Due to the story of
ocaml-freestandng/Solo5/Xen, we are currently stuck to few targets (Unix, Solo5 & Xen) and an extension of them need an incredible work on third-part libraries (
mirage-crypto will must compile a third artifact according to the new target).
MirageOS 4 wants to solve that and propose an other way to link third-part libraries - more concretely, we will compile locally third-part libraries according to your requested target (and C flags) and solve by this way the question about C stubs.
The solution focus on:
- the extension of targets (including cross-compiled targets)
- third-part libraries (with C stubs)
As you can see, we don’t talk about scheduler here because several questions comes:
type 'a iocurrently specialized to
'a Lwt.t. Even if most of our libraries abstract this type, it’s not systematically the true. For instance,
ocaml-gitand Irmin uses
- the main loop, as you can see here is defined by the back-end chosen (where
So a move to
async (with MirageOS 4 - which is not released yet ) implies:
- some patches on
ocaml-freestanding(to implement missing C functions)
- a new
mirageback-end (with another implementation of the main loop)
- an systemic abstraction (with functors) of some famous MirageOS libraries
If you look into details, most of issues is about a inherent technical debt about our choices in the past. Anything is possible but should we spend our time to that? As I said most of times, we are few to maintain MirageOS and we must choose intelligently our path. For my perspective, I never used
async and I don’t need it when
lwt exists on the other side (and fits well in our case) - but I’m surely biased when I did my first internship at ocsigen !
Of course, if anyone wants
async with MirageOS, the path is open - and we will gladly help you.
Thank you for the detailed answer @dinosaure. Much appreciated.