lwt icon indicating copy to clipboard operation
lwt copied to clipboard

Allow the Esperanto support for `lwt`

Open dinosaure opened this issue 3 years ago • 10 comments

This PR wants to fix the support with the Esperanto & Cosmopolitan. Esperanto is an OCaml toolchain which allows us to compile an OCaml application. The resulted application (an executable) should run anywhere (Linux, Mac, Windows and BSD family).

Currently, a simple project in OCaml can be compiled with Esperanto but a larger project which probably uses lwt can not be compiled because few details. This PR wants to fix these details and allow us to take an OCaml application which depends on lwt and be able to build-once an application which should run-anywhere.

This PR is a draft because a special commit (the second to last) is probably the most invasive and dependant to Esperanto but I can probably find an other situation than what I proposed. Feel free to comment the rest of commits which are valid for us for the Esperanto toolchain. I tried to be less invasive as I can.

dinosaure avatar May 23 '22 15:05 dinosaure

From this PR, this simple code works for Ubuntu:

open Lwt.Infix

let rec full_write fd buf off len =
  Lwt_unix.write fd buf off len >>= fun len' ->
  if len - len' > 0
  then full_write fd buf (off + len') (len - len')
  else Lwt.return_unit

let tmp = Bytes.create 0x1000

let rec cat () =
  Lwt.catch begin fun () ->
    Lwt_unix.read Lwt_unix.stdin tmp 0 (Bytes.length tmp) >>= fun len ->
    match len with
    | 0 -> Lwt.return_unit
    | len -> full_write Lwt_unix.stdout tmp 0 len >>= cat
  end @@ function
  | End_of_file -> Lwt.return_unit
  | exn -> raise exn

let () = Lwt_main.run (cat ())

If you want to try, you need to create a dune file, a dune-workspace and a opam file:

$ cat >dune <<EOF
(executable
 (enabled_if
  (= %{context_name} esperanto))
 (libraries lwt.unix)
 (modules cat_lwt_unix)
 (name cat_lwt_unix))

(rule
 (target cat_lwt_unix.com)
 (enabled_if
  (= %{context_name} esperanto))
 (mode promote)
 (deps cat_lwt_unix.exe)
 (action (run objcopy -S -O binary %{deps} %{target})))
EOF
$ cat >dune-workspace <<EOF
(lang dune 2.0)
(context (default))
(context
 (default
  (name esperanto)
  (toolchain esperanto)
  (merlin)
  (host default)))
EOF
$ cat >cat_lwt_unix.opam <<EOF
opam-version: "2.0"
name:         "cat-lwt-unix"
maintainer:   [ "Romain Calascibetta <[email protected]>" ]
authors:      [ "Romain Calascibetta <[email protected]>" ]
homepage:     "https://github.com/dinosaure/esperanto"
bug-reports:  "https://github.com/dinosaure/esperanto/issues"
dev-repo:     "git+https://github.com/dinosaure/esperanto"
doc:          "https://dinosaure.github.io/esperanto/"
license:      "MIT"
synopsis:     "cat tool with lwt and compiled with esperanto"
description:  "cat tool with lwt and compiled with esperanto"

build: [
  [ "dune" "build" "-p" name "-j" jobs ]
]
install:  [
  [ "dune" "install" "-p" name ] {with-test}
]

depends: [
  "ocaml"           {>= "4.08.0"}
  "dune"            {>= "2.6.0"}
  "lwt"
]

pin-depends: [
  [ "lwt.dev" "git+https://github.com/dinosaure/lwt.git#69419f4352d1ae0e60039275ec9da893c505e2c6" ]
]
EOF

Then, to be able to cross-compile this little project, you must use opam monorepo to compile dependencies into the same context:

$ opam pin add -y https://github.com/dinosaure/esperanto.git
$ opam monorepo lock
$ opam monorepo pull
$ dune build
$ bash -c "echo 'Hello World!' | ./cat_lwt_unix.com"
Hello World!

dinosaure avatar Jun 01 '22 11:06 dinosaure

This PR is definitely ready:

  1. it seems that the behavior of discover.exe is the same as before - however, many issues persist about the cross-compilation but I don't have the time to look deeper on that. At least, I added some comments to explain what is going on. The result is: we can build an Esperanto/Cosmopolitan application only if libev is not installed (otherwise, lwt will try to bring it even if we want to compile everything into a cross-compiled context).
  2. The example above still work on my machine
  3. Each commits are well commented for further lecture
  4. The CI fails for other reasons than this PR

If you have any question, don't hesitate but I hope that I clearly described everything!

dinosaure avatar Jun 01 '22 13:06 dinosaure

Thanks for this PR! I like the idea behind esperanto/cosmopolitan very nice! Some comments about the MR specifically:

  • It touches the part of Lwt that I'm not familiar with and not really competent to check (I haven't done any C in too long, I would need a refresher).
  • If we go this way (which I'd be inclined to do, but would like additional opinions as well) we probably need some new tests in the CI to actually check the portability. It's not needed right now though, we can wait until it's a feature we announce we support.
  • The CI failure is on windows and I don't have a machine to try to reproduce things on. They seem to be related to opam build of ocaml-config and a checksum fail at that. So probably some opam repo issue. I've restarted the jobs to see if it's transient. (EDIT: they are not transient, I'll have to check that separately)
  • There are plans to drop support for some old versions of OCaml (keeping only 4.08+). This should simplify the code somewhat, and especially the C bindings which are full of #if OCAML_VERSION …. I don't think it will interfere with your PR but something we might want to keep in mind. It might be useful if/when esperanto supports more OCaml versions.

Re: libev
It might be related to https://github.com/ocsigen/lwt/commit/e9a9c7bde4074bd8a0cee531a7789d93628fa46e and you might have to pass --libev-default=false explicitly to dune exec src/unix/config/discover.exe. I haven't tinkered with this yet, but I can have a more in-depth look if you need me to.

raphael-proust avatar Jun 02 '22 06:06 raphael-proust

It might be useful if/when esperanto supports more OCaml versions.

Currently, Esperanto support 4.12, 4.13 and 4.14 (MirageOS support) but I can not go further when it requires more time that I don't really have.

dinosaure avatar Jun 02 '22 10:06 dinosaure

Currently, Esperanto support 4.12, 4.13 and 4.14 (MirageOS support)

Nice! I got the 4.14 support from the Esperanto README:

Currently, we only support OCaml 4.14

This might need updating.

Otherwise I had a longer look and I don't think the two changesets will conflict. So we should be good on that front.

raphael-proust avatar Jun 02 '22 11:06 raphael-proust

I added a CI which compile and run a simple LWT program with esperanto toolchain on Ubuntu (latest) and it's work. I would like to clarify only one point: lwt + esperanto does not work, for the moment, on Windows due to a lack of portability of the pthreads library (the issue is here https://github.com/dinosaure/esperanto/issues/11 for more details). A possible solution was found however, but I need much more times to complete this task.

Regardless the Windows support, this PR is ready - however, you should get some conflict with #953.

dinosaure avatar Jun 15 '22 09:06 dinosaure

@dinosaure Cosmopolitan Libc has pthreads support now. https://github.com/jart/cosmopolitan/releases/tag/2.1 If there's an issue with setcontext() and getcontext() that are causing issues for fibers, then let me know and I'll fix it.

jart avatar Sep 30 '22 01:09 jart

Currently, this PR can compile a simple program. However, the example (a simple cat) hangs at the end. I will try to debug that as soon as I can.

dinosaure avatar Feb 06 '23 10:02 dinosaure

This PR is actually ready, the CI works on my side and we are able to compile & run a Cosmopolitan binary with lwt :tada:. Feel free to redo a final review.

dinosaure avatar Jun 05 '23 13:06 dinosaure

Might be interesting to checkout this patch to GCC, allowing compilation of unmodified code with Cosmo, by compiler rewriting uses of preprocessor constants. https://ahgamut.github.io/2023/07/13/patching-gcc-cosmo/ Does Lwt builds unmodified with this patch?

MisterDA avatar Jul 14 '23 06:07 MisterDA