From 879d94e55b7a4fa454b0df640bae2103d48690d9 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Tue, 25 May 2021 11:20:53 +0100 Subject: [PATCH] Add eio_main library to select backend This allows writing portable applications without depending on a specific backend such as Eunix. --- README.md | 20 ++++++++++++-------- dune | 2 +- dune-project | 7 +++++++ eio_main.opam | 29 +++++++++++++++++++++++++++++ lib_main/dune | 4 ++++ lib_main/eio_main.ml | 1 + 6 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 eio_main.opam create mode 100644 lib_main/dune create mode 100644 lib_main/eio_main.ml diff --git a/README.md b/README.md index 808fecd..4b7ae69 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ It is able to run a web-server with good performance, but most features are stil - `eio` provides a high-level, cross-platform OS API. - `eunix` provides a Linux io-uring backend for these APIs, plus a low-level API that can be used directly (in non-portable code). +- `eio_main` selects an appropriate backend (e.g. `eunix`), depending on your platform. - `ctf` provides tracing support. ## Getting started @@ -78,14 +79,14 @@ git clone --recursive https://github.com/ocaml-multicore/eio.git cd eio opam pin -yn ./ocaml-uring opam pin -yn . -opam depext -i eunix utop +opam depext -i eio_main utop ``` -To try out the examples interactively, run `utop` and `require` the `eunix` library. +To try out the examples interactively, run `utop` and `require` the `eio_main` library. It is also convenient to open the `Fibreslib` module: ```ocaml -# #require "eunix";; +# #require "eio_main";; # open Fibreslib;; ``` @@ -97,10 +98,10 @@ let main ~stdout = Eio.Sink.write stdout ~src ``` -To run it, we use `Eunix.run` to run the event loop and call it from there: +To run it, we use `Eio_main.run` to run the event loop and call it from there: ```ocaml -# Eunix.run @@ fun env -> +# Eio_main.run @@ fun env -> main ~stdout:(Eio.Stdenv.stdout env);; Hello, world! - : unit = () @@ -113,13 +114,16 @@ Note that: - The type of the `main` function here tells us that this program only interacts via `stdout`. +- `Eio_main.run` automatically calls the appropriate run function for your platform. + For example, on Linux this will call `Eunix.run`. For non-portable code you can use the platform-specific library directly. + ## Testing with mocks Because external resources are provided to `main` as arguments, we can easily replace them with mocks for testing. e.g. ```ocaml -# Eunix.run @@ fun _env -> +# Eio_main.run @@ fun _env -> let buffer = Buffer.create 20 in main ~stdout:(Eio.Sink.of_buffer buffer); traceln "Main would print %S" (Buffer.contents buffer);; @@ -135,7 +139,7 @@ so let's make a little wrapper to simplify future examples: ```ocaml let run fn = - Eunix.run @@ fun _ -> + Eio_main.run @@ fun _ -> try fn () with Failure msg -> traceln "Error: %s" msg ``` @@ -286,7 +290,7 @@ And here is the equivalent using Eio: ```ocaml # let () = - Eunix.run @@ fun env -> + Eio_main.run @@ fun env -> let src = Eio.Stdenv.stdin env in let dst = Eio.Stdenv.stdout env in Eio.Sink.write dst ~src diff --git a/dune b/dune index 58c7f8d..1479908 100644 --- a/dune +++ b/dune @@ -1,3 +1,3 @@ (mdx - (packages eunix) + (packages eio_main) (files README.md)) diff --git a/dune-project b/dune-project index 04b0b35..2ca92a2 100644 --- a/dune-project +++ b/dune-project @@ -48,4 +48,11 @@ (ocplib-endian (>= 1.1)) (mtime (>= 1.2.0)) (cstruct (>= 6.0.0)))) +(package + (name eio_main) + (synopsis "Effect-based direct-style IO mainloop for OCaml") + (description + "Selects an appropriate Eio backend for the current platform.") + (depends + (eunix (= :version)))) (using mdx 0.1) diff --git a/eio_main.opam b/eio_main.opam new file mode 100644 index 0000000..12300d4 --- /dev/null +++ b/eio_main.opam @@ -0,0 +1,29 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "Effect-based direct-style IO mainloop for OCaml" +description: "Selects an appropriate Eio backend for the current platform." +maintainer: ["anil@recoil.org"] +authors: ["Anil Madhavapeddy" "Thomas Leonard"] +license: "ISC" +homepage: "https://github.com/ocaml-multicore/eio" +bug-reports: "https://github.com/ocaml-multicore/eio/issues" +depends: [ + "dune" {>= "2.8"} + "eunix" {= version} + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/ocaml-multicore/eio.git" diff --git a/lib_main/dune b/lib_main/dune new file mode 100644 index 0000000..f763933 --- /dev/null +++ b/lib_main/dune @@ -0,0 +1,4 @@ +(library + (name eio_main) + (public_name eio_main) + (libraries eunix)) diff --git a/lib_main/eio_main.ml b/lib_main/eio_main.ml new file mode 100644 index 0000000..cb18dd2 --- /dev/null +++ b/lib_main/eio_main.ml @@ -0,0 +1 @@ +let run fn = Eunix.run (fun env -> fn (env :> Eio.Stdenv.t))