├── .gitattributes ├── .gitignore ├── README.md ├── bench ├── dune ├── fibonacci.re ├── message_passing_across_workers.re ├── message_passing_in_worker.re ├── spawn.re └── startup.re ├── docs └── design.md ├── dune-project ├── esy.lock ├── .gitattributes ├── .gitignore ├── index.json ├── opam │ ├── alcotest.0.8.5 │ │ └── opam │ ├── astring.0.8.3 │ │ └── opam │ ├── base-bytes.base │ │ └── opam │ ├── base-threads.base │ │ └── opam │ ├── base-unix.base │ │ └── opam │ ├── benchmark.1.6 │ │ └── opam │ ├── biniou.1.2.0 │ │ └── opam │ ├── cmdliner.1.0.3 │ │ └── opam │ ├── conf-m4.1 │ │ └── opam │ ├── conf-which.1 │ │ └── opam │ ├── cppo.1.6.5 │ │ └── opam │ ├── dune.1.8.2 │ │ └── opam │ ├── easy-format.1.3.1 │ │ └── opam │ ├── fmt.0.8.5 │ │ └── opam │ ├── fpath.0.7.2 │ │ └── opam │ ├── jbuilder.transition │ │ └── opam │ ├── logs.0.6.2 │ │ └── opam │ ├── lwt.4.1.0 │ │ └── opam │ ├── menhir.20181113 │ │ └── opam │ ├── merlin-extend.0.3 │ │ └── opam │ ├── merlin.3.2.2 │ │ └── opam │ ├── ocaml-migrate-parsetree.1.2.0 │ │ └── opam │ ├── ocamlbuild.0.14.0 │ │ └── opam │ ├── ocamlfind.1.8.0 │ │ ├── files │ │ │ ├── ocaml-stub │ │ │ └── ocamlfind.install │ │ └── opam │ ├── odoc.1.4.0 │ │ └── opam │ ├── ounit.2.0.8 │ │ └── opam │ ├── ppx_derivers.1.0 │ │ └── opam │ ├── qcheck-alcotest.0.9 │ │ └── opam │ ├── qcheck-core.0.9 │ │ └── opam │ ├── qcheck-ounit.0.9 │ │ └── opam │ ├── qcheck.0.9 │ │ └── opam │ ├── re.1.8.0 │ │ └── opam │ ├── result.1.3 │ │ └── opam │ ├── seq.base │ │ ├── files │ │ │ ├── META.seq │ │ │ └── seq.install │ │ └── opam │ ├── topkg.1.0.0 │ │ └── opam │ ├── tyxml.4.3.0 │ │ └── opam │ ├── uchar.0.0.2 │ │ └── opam │ ├── uuidm.0.9.7 │ │ └── opam │ ├── uutf.1.0.2 │ │ └── opam │ └── yojson.1.7.0 │ │ └── opam └── overrides │ ├── opam__s__dune_opam__c__1.8.2_opam_override │ └── package.json │ ├── opam__s__merlin_extend_opam__c__0.3_opam_override │ ├── files │ │ └── merlin-extend-winfix.patch │ └── package.json │ ├── opam__s__ocamlbuild_opam__c__0.14.0_opam_override │ ├── files │ │ └── ocamlbuild-0.14.0.patch │ └── package.json │ └── opam__s__ocamlfind_opam__c__1.8.0_opam_override │ ├── files │ └── findlib-1.8.0.patch │ └── package.json ├── examples ├── 01_spawning_processes │ ├── dune │ └── main.re ├── 02_basic_message_passing │ ├── dune │ └── main.re ├── README.md ├── dummy.re ├── dune ├── dune-project ├── esy.lock │ ├── .gitattributes │ ├── .gitignore │ ├── index.json │ ├── opam │ │ ├── astring.0.8.3 │ │ │ └── opam │ │ ├── base-bytes.base │ │ │ └── opam │ │ ├── base-threads.base │ │ │ └── opam │ │ ├── base-unix.base │ │ │ └── opam │ │ ├── biniou.1.2.0 │ │ │ └── opam │ │ ├── conf-m4.1 │ │ │ └── opam │ │ ├── conf-pkg-config.1.1 │ │ │ └── opam │ │ ├── conf-sdl2.1 │ │ │ └── opam │ │ ├── conf-which.1 │ │ │ └── opam │ │ ├── cppo.1.6.5 │ │ │ └── opam │ │ ├── ctypes-foreign.0.4.0 │ │ │ └── opam │ │ ├── ctypes.0.14.0 │ │ │ └── opam │ │ ├── dune.1.7.3 │ │ │ └── opam │ │ ├── easy-format.1.3.1 │ │ │ └── opam │ │ ├── fmt.0.8.5 │ │ │ └── opam │ │ ├── integers.0.2.2 │ │ │ └── opam │ │ ├── jbuilder.transition │ │ │ └── opam │ │ ├── logs.0.6.2 │ │ │ └── opam │ │ ├── lwt.4.1.0 │ │ │ └── opam │ │ ├── menhir.20181113 │ │ │ └── opam │ │ ├── merlin-extend.0.3 │ │ │ └── opam │ │ ├── merlin.3.2.2 │ │ │ └── opam │ │ ├── ocaml-migrate-parsetree.1.2.0 │ │ │ └── opam │ │ ├── ocamlbuild.0.14.0 │ │ │ └── opam │ │ ├── ocamlfind.1.8.0 │ │ │ ├── files │ │ │ │ ├── ocaml-stub │ │ │ │ └── ocamlfind.install │ │ │ └── opam │ │ ├── ocb-stubblr.0.1.1-1 │ │ │ ├── files │ │ │ │ ├── custom-cclib.patch │ │ │ │ └── use-OPAM_SWITCH_PREFIX.patch │ │ │ └── opam │ │ ├── ppx_derivers.1.0 │ │ │ └── opam │ │ ├── re.1.8.0 │ │ │ └── opam │ │ ├── reason.3.4.0 │ │ │ └── opam │ │ ├── result.1.3 │ │ │ └── opam │ │ ├── seq.base │ │ │ ├── files │ │ │ │ ├── META.seq │ │ │ │ └── seq.install │ │ │ └── opam │ │ ├── topkg.1.0.0 │ │ │ └── opam │ │ ├── tsdl.0.9.6 │ │ │ └── opam │ │ ├── uchar.0.0.2 │ │ │ └── opam │ │ └── yojson.1.7.0 │ │ │ └── opam │ └── overrides │ │ ├── opam__s__conf_pkg_config_opam__c__1.1_opam_override │ │ └── package.json │ │ ├── opam__s__conf_sdl2_opam__c__1_opam_override │ │ └── package.json │ │ ├── opam__s__ctypes_opam__c__0.14.0_opam_override │ │ └── package.json │ │ ├── opam__s__dune_opam__c__1.7.3_opam_override │ │ └── package.json │ │ ├── opam__s__merlin_extend_opam__c__0.3_opam_override │ │ ├── files │ │ │ └── merlin-extend-winfix.patch │ │ └── package.json │ │ ├── opam__s__ocamlbuild_opam__c__0.14.0_opam_override │ │ ├── files │ │ │ └── ocamlbuild-0.14.0.patch │ │ └── package.json │ │ ├── opam__s__ocamlfind_opam__c__1.8.0_opam_override │ │ ├── files │ │ │ └── findlib-1.8.0.patch │ │ └── package.json │ │ ├── opam__s__ocb_stubblr_opam__c__0.1.1_1_opam_override │ │ └── package.json │ │ └── opam__s__tsdl_opam__c__0.9.6_opam_override │ │ └── package.json ├── package.json └── sdl │ ├── Gui_test.re │ ├── dune │ ├── message_codec.re │ └── sdl_ctx.re ├── package.json ├── reactor.opam ├── src ├── bytecode │ ├── bytecode.re │ └── dune ├── coordinator │ ├── coordinator.re │ ├── coordinator.rei │ ├── dune │ └── packet.re ├── node │ ├── dune │ ├── node.re │ ├── node.rei │ ├── policy.re │ ├── policy.rei │ └── scheduler_view.re ├── platform │ ├── dune │ ├── platform.re │ ├── platform.rei │ └── process.re ├── process │ ├── dune │ ├── index.mld │ ├── mailbox.re │ ├── mailbox.rei │ ├── message.re │ ├── message.rei │ ├── pid.re │ ├── process.re │ └── process.rei ├── reactor │ ├── dune │ └── reactor.re ├── registry │ ├── dune │ ├── registry.re │ └── registry.rei ├── scheduler │ ├── dune │ ├── scheduler.re │ └── scheduler.rei ├── task_queue │ ├── dune │ ├── task_queue.re │ └── task_queue.rei └── tasks │ ├── dune │ ├── tasks.re │ └── tasks.rei ├── test ├── dune ├── process │ ├── dune │ └── pid_test.re └── runtime_test.re └── tools ├── dune └── log_splitter.re /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-vendored 2 | *.re linguist-language=Reason 3 | *.rei linguist-language=Reason 4 | *.js linguist-generated=true 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .merlin 3 | .bsb.lock 4 | npm-debug.log 5 | /lib/bs/ 6 | /node_modules/ 7 | spec/*.toolbox 8 | .tla 9 | *.zip 10 | tags 11 | *.swp 12 | 13 | _build 14 | _esy 15 | *.install 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 reactor 2 | > Native Actors for Reason and OCaml 3 | 4 | **Status**: ALPHA. Ready for the adventurous 🤠 5 | 6 | ## Getting Started 7 | 8 | If you're just starting out, have a look at the [Examples](/examples) section. 9 | It includes examples in the form of _labs_ that you can play around with and 10 | modify to get a better grasp of the core features of the library. 11 | 12 | ## Contributing 13 | 14 | This project is setup and run with `esy`, so make sure you have that installed. 15 | 16 | After that it's an `esy install` and `esy build` away. 17 | 18 | Tests can be run with `esy dune runtest`. 19 | 20 | Benchmarks can be run with `esy dune exec ./bench/{bench_name}.exe` 21 | 22 | To run the examples you can use: 23 | 24 | ``` 25 | λ esy @examples/package.json dune exec --watch ./examples/sdl/gui_test.exe 26 | ``` 27 | -------------------------------------------------------------------------------- /bench/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name spawn) 3 | (modules spawn) 4 | (libraries benchmark reactor logs logs.fmt fmt fmt.tty)) 5 | 6 | (executable 7 | (name startup) 8 | (modules startup) 9 | (libraries benchmark reactor)) 10 | 11 | (executable 12 | (name message_passing_in_worker) 13 | (modules message_passing_in_worker) 14 | (libraries benchmark reactor logs logs.fmt fmt fmt.tty)) 15 | 16 | (executable 17 | (name message_passing_across_workers) 18 | (modules message_passing_across_workers) 19 | (libraries benchmark reactor logs logs.fmt fmt fmt.tty)) 20 | 21 | (executable 22 | (name fibonacci) 23 | (modules fibonacci) 24 | (libraries benchmark reactor logs logs.fmt fmt fmt.tty)) 25 | -------------------------------------------------------------------------------- /bench/fibonacci.re: -------------------------------------------------------------------------------- 1 | open Reactor.System; 2 | 3 | /** Logging setup */ 4 | Fmt_tty.setup_std_outputs(); 5 | Logs.set_level(Some(Logs.App)); 6 | Logs.set_reporter(Logs_fmt.reporter()); 7 | 8 | /** System setup */ 9 | let begin_at = Unix.time(); 10 | Reactor.Node.(Policy.default() |> setup); 11 | 12 | spawn( 13 | (_, (last, this, count)) => 14 | switch (count) { 15 | | 1_000_000 => 16 | Logs.app(m => m("%d", this)); 17 | exit(); 18 | | _ => `Become((this, last + this, count + 1)) 19 | }, 20 | (0, 1, 0), 21 | ) 22 | |> ignore; 23 | 24 | Reactor.Node.run(); 25 | 26 | let end_at = Unix.time(); 27 | let delta = end_at -. begin_at; 28 | Logs.app(m => m("Computed 1,000,000th Fibonacci number in: %.2fs", delta)); 29 | -------------------------------------------------------------------------------- /bench/message_passing_across_workers.re: -------------------------------------------------------------------------------- 1 | open Reactor.System; 2 | 3 | /** Logging setup */ 4 | Fmt_tty.setup_std_outputs(); 5 | Logs.set_level(Some(Logs.App)); 6 | Logs.set_reporter(Logs_fmt.reporter()); 7 | 8 | /** System setup */ 9 | let begin_at = Unix.time(); 10 | Reactor.Node.(Policy.default() |> setup); 11 | 12 | let msg = Bytes.(create(64998) |> to_string); 13 | 14 | let counter = 15 | spawn( 16 | (ctx, msg_count) => 17 | switch (ctx.recv(), msg_count) { 18 | | (_, 0) => exit() 19 | | (Some(_), _) => `Become(msg_count - 1) 20 | | _ => `Become(msg_count) 21 | }, 22 | 100_000, 23 | ); 24 | 25 | let sender = 26 | spawn( 27 | (_, receiver) => { 28 | receiver <- msg; 29 | `Become(receiver); 30 | }, 31 | counter, 32 | ); 33 | 34 | Reactor.Node.run(); 35 | 36 | let end_at = Unix.time(); 37 | let delta = end_at -. begin_at; 38 | Logs.app(m => m("Send 64998 bytes x 1,000 across workers in: %.2fs", delta)); 39 | -------------------------------------------------------------------------------- /bench/message_passing_in_worker.re: -------------------------------------------------------------------------------- 1 | open Reactor.System; 2 | 3 | /** Logging setup */ 4 | Fmt_tty.setup_std_outputs(); 5 | Logs.set_level(Some(Logs.App)); 6 | Logs.set_reporter(Logs_fmt.reporter()); 7 | 8 | /** System setup */ 9 | let begin_at = Unix.time(); 10 | Reactor.Node.(Policy.default() |> setup); 11 | 12 | let msg = Bytes.(create(64998) |> to_string); 13 | 14 | let pid = 15 | spawn( 16 | (ctx, msg_count) => 17 | switch (ctx.recv(), msg_count) { 18 | | (_, 0) => exit() 19 | | (Some(msg), _) => 20 | ctx.self() <- msg; 21 | `Become(msg_count - 1); 22 | | _ => `Become(msg_count) 23 | }, 24 | 100_000, 25 | ); 26 | 27 | pid <- msg; 28 | 29 | Reactor.Node.run(); 30 | 31 | let end_at = Unix.time(); 32 | let delta = end_at -. begin_at; 33 | Logs.app(m => m("Send 64998 bytes x 100,000 in a worker in: %.2fs", delta)); 34 | -------------------------------------------------------------------------------- /bench/spawn.re: -------------------------------------------------------------------------------- 1 | open Reactor.System; 2 | 3 | /** Logging setup */ 4 | Fmt_tty.setup_std_outputs(); 5 | Logs.set_level(Some(Logs.App)); 6 | Logs.set_reporter(Logs_fmt.reporter()); 7 | 8 | /** System setup */ 9 | let begin_at = Unix.time(); 10 | Reactor.Node.(Policy.default() |> setup); 11 | 12 | let spawn_counter = pid => 13 | spawn((_ctx, _) => { 14 | pid <- "add"; 15 | `Terminate; 16 | }); 17 | 18 | let _ = 19 | spawn( 20 | (ctx, (proc_count, i)) => 21 | switch (ctx.recv(), i + 1) { 22 | | (_, 0) => 23 | Array.make(proc_count, 0) 24 | |> Array.map(spawn_counter(ctx.self())) 25 | |> ignore; 26 | Logs.app(m => m("%d actors spawned", proc_count)); 27 | `Become((proc_count, 0)); 28 | | (Some("add"), i') => 29 | switch (i' == proc_count) { 30 | | true => 31 | Logs.app(m => m("%d actors finished.", proc_count)); 32 | exit(); 33 | | _ => `Become((proc_count, i')) 34 | } 35 | | (_, _) => `Become((proc_count, i)) 36 | }, 37 | (1_000_000, (-1)), 38 | ); 39 | 40 | Reactor.Node.run(); 41 | 42 | let end_at = Unix.time(); 43 | let delta = end_at -. begin_at; 44 | Logs.app(m => m("Spawned and terminated 1,000,000 Actors in: %.2fs", delta)); 45 | -------------------------------------------------------------------------------- /bench/startup.re: -------------------------------------------------------------------------------- 1 | open Reactor.System; 2 | 3 | Fmt_tty.setup_std_outputs(); 4 | // Logs.set_level(Some(Logs.Debug)); 5 | Logs.set_reporter(Logs_fmt.reporter()); 6 | 7 | /** Logging setup */ 8 | let result = 9 | Benchmark.latencyN( 10 | ~repeat=10, 11 | 10L, 12 | [ 13 | ( 14 | "Startup", 15 | () => { 16 | Reactor.Node.(Policy.default() |> setup); 17 | let _ = spawn((_, _) => exit(), ()); 18 | Reactor.Node.run(); 19 | }, 20 | (), 21 | ), 22 | ], 23 | ); 24 | 25 | Logs.app(m => m("[%d] Startup cost", Unix.getpid())); 26 | Benchmark.tabulate(result); 27 | -------------------------------------------------------------------------------- /docs/design.md: -------------------------------------------------------------------------------- 1 | # Reactor's Design 2 | 3 | ## Startup 4 | 5 | When the application is set up for the first time, the current OS process 6 | will become a __Node__. Its job will be to bootstrap, keep alive, and 7 | coordinate messages across __Schedulers__. These Schedulers are separate OS 8 | processes and have their own lifecycles. 9 | 10 | ``` 11 | +----------------+ +------------------+ +--------------+ 12 | | Main Process | +==>+ Child Process #0 +-----+ Scheduler #0 | 13 | +-----+----------+ | +------------------+ +--------------+ 14 | | | 15 | | +------+ | +------------------+ +--------------+ 16 | +---+ Node +<==+==>+ Child Process #1 +-----+ Scheduler #1 | 17 | +------+ | +------------------+ +--------------+ 18 | | 19 | | +------------------+ +--------------+ 20 | +==>+ Child Process #2 +-----+ Scheduler #2 | 21 | | +------------------+ +--------------+ 22 | | 23 | | +------------------+ +--------------+ 24 | +==>+ Child Process #3 +-----+ Scheduler #3 | 25 | +------------------+ +--------------+ 26 | 27 | ``` 28 | 29 | All communication between processes is happening via Unix pipes or the 30 | equivalent mechanism in other OS. 31 | 32 | Because of the nature of Unix process forking, the Main process _becomes_ one 33 | of it's children by copying the current memory. This means that we want to set 34 | up the Node as early on as possible to avoid duplicating data we don't really 35 | need in the Schedulers. 36 | 37 | When a node is set up, it will create a _process pool_. Each child process will 38 | be set up as a Scheduler, and, for each Scheduler set up, the Node will create 39 | a _view_ of that Scheduler to keep track of them. 40 | 41 | ## Scheduling Loop 42 | 43 | As soon as the Scheduler processes start up, they constantly loop through the 44 | following list: 45 | 46 | 1. Check if the scheduler should halt, and if it shouldn't then: 47 | 1. Check if it can read from the Node 48 | 2. If there are tasks to read, read one and queue it 49 | 3. If there are tasks in the queue, pick the next one and handle it 50 | 4. Iterate on any open Lwt promises 51 | 5. Loop back to 1. 52 | 2. If it should halt, it'll break the loop and continue the execution of the 53 | process to it's end. 54 | 55 | Step `1.3` can be broken down into: 56 | 57 | * Handling tasks from the coordinator 58 | * Handling tasks from itself — as a locality optimization, certain tasks that 59 | will be eventually handled within the same scheduler are simply not sent to 60 | the coordinator. 61 | * Computing process reductions — this is what actually executes actors in the 62 | system. 63 | 64 | The Node, acting as a coordinator of schedulers, goes through the following 65 | list in a loop: 66 | 67 | 1. Should the node shut down? If it should, quit the loop, else continue. 68 | 2. If there's any commands to be read, queue them up 69 | 3. If there's any schedulers ready to receive commands and there are commands 70 | to send, send them to the schedulers. 71 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 1.6) 2 | (name reactor) 3 | (using fmt 1.1) 4 | -------------------------------------------------------------------------------- /esy.lock/.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | # Set eol to LF so files aren't converted to CRLF-eol on Windows. 3 | * text eol=lf 4 | -------------------------------------------------------------------------------- /esy.lock/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Reset any possible .gitignore, we want all esy.lock to be un-ignored. 3 | !* 4 | -------------------------------------------------------------------------------- /esy.lock/opam/alcotest.0.8.5/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "thomas@gazagnaire.org" 3 | authors: "Thomas Gazagnaire" 4 | homepage: "https://github.com/mirage/alcotest/" 5 | dev-repo: "git+https://github.com/mirage/alcotest.git" 6 | bug-reports: "https://github.com/mirage/alcotest/issues/" 7 | license: "ISC" 8 | doc: "https://mirage.github.io/alcotest/" 9 | 10 | build: [ 11 | ["dune" "subst"] {pinned} 12 | ["dune" "build" "-p" name "-j" jobs] 13 | ["dune" "runtest" "-p" name "-j" jobs] {with-test} 14 | ] 15 | 16 | depends: [ 17 | "dune" {build & >= "1.1.0"} 18 | "ocaml" {>= "4.02.3"} 19 | "fmt" {>= "0.8.0"} 20 | "astring" 21 | "result" 22 | "cmdliner" 23 | "uuidm" 24 | ] 25 | 26 | synopsis: "Alcotest is a lightweight and colourful test framework" 27 | 28 | description: """ 29 | Alcotest exposes simple interface to perform unit tests. It exposes 30 | a simple TESTABLE module type, a check function to assert test 31 | predicates and a run function to perform a list of unit -> unit 32 | test callbacks. 33 | 34 | Alcotest provides a quiet and colorful output where only faulty runs 35 | are fully displayed at the end of the run (with the full logs ready to 36 | inspect), with a simple (yet expressive) query language to select the 37 | tests to run. 38 | """ 39 | url { 40 | src: 41 | "https://github.com/mirage/alcotest/releases/download/0.8.5/alcotest-0.8.5.tbz" 42 | checksum: "md5=2db36741c413ab93391ecc1f983aa804" 43 | } 44 | -------------------------------------------------------------------------------- /esy.lock/opam/astring.0.8.3/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/astring" 5 | doc: "http://erratique.ch/software/astring/doc" 6 | dev-repo: "git+http://erratique.ch/repos/astring.git" 7 | bug-reports: "https://github.com/dbuenzli/astring/issues" 8 | tags: [ "string" "org:erratique" ] 9 | license: "ISC" 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {build} 14 | "topkg" {build} 15 | "base-bytes" 16 | ] 17 | build: [[ 18 | "ocaml" "pkg/pkg.ml" "build" 19 | "--pinned" "%{pinned}%" ]] 20 | synopsis: "Alternative String module for OCaml" 21 | description: """ 22 | Astring exposes an alternative `String` module for OCaml. This module 23 | tries to balance minimality and expressiveness for basic, index-free, 24 | string processing and provides types and functions for substrings, 25 | string sets and string maps. 26 | 27 | Remaining compatible with the OCaml `String` module is a non-goal. The 28 | `String` module exposed by Astring has exception safe functions, 29 | removes deprecated and rarely used functions, alters some signatures 30 | and names, adds a few missing functions and fully exploits OCaml's 31 | newfound string immutability. 32 | 33 | Astring depends only on the OCaml standard library. It is distributed 34 | under the ISC license.""" 35 | url { 36 | src: "http://erratique.ch/software/astring/releases/astring-0.8.3.tbz" 37 | checksum: "md5=c5bf6352b9ac27fbeab342740f4fa870" 38 | } 39 | -------------------------------------------------------------------------------- /esy.lock/opam/base-bytes.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: " " 3 | authors: " " 4 | homepage: " " 5 | depends: [ 6 | "ocaml" {>= "4.02.0"} 7 | "ocamlfind" {>= "1.5.3"} 8 | ] 9 | synopsis: "Bytes library distributed with the OCaml compiler" 10 | -------------------------------------------------------------------------------- /esy.lock/opam/base-threads.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "https://github.com/ocaml/opam-repository/issues" 3 | description: """ 4 | Threads library distributed with the OCaml compiler 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /esy.lock/opam/base-unix.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "https://github.com/ocaml/opam-repository/issues" 3 | description: """ 4 | Unix library distributed with the OCaml compiler 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /esy.lock/opam/benchmark.1.6/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Christophe Troestler " 3 | authors: ["Christophe Troestler " 4 | "Doug Bagley"] 5 | tags: ["benchmark"] 6 | license: "LGPL-3.0 with OCaml linking exception" 7 | homepage: "https://github.com/Chris00/ocaml-benchmark" 8 | dev-repo: "git+https://github.com/Chris00/ocaml-benchmark.git" 9 | bug-reports: "https://github.com/Chris00/ocaml-benchmark/issues" 10 | doc: "https://Chris00.github.io/ocaml-benchmark/doc" 11 | build: [ 12 | [ "dune" "subst" ] {pinned} 13 | [ "dune" "build" "-p" name "-j" jobs ] 14 | ] 15 | depends: [ 16 | "ocaml" {>= "3.12.0"} 17 | "dune" {build} 18 | "base-unix" 19 | ] 20 | synopsis: "Benchmark running times of code" 21 | description: """ 22 | This module provides a set of tools to measure the running times of 23 | your functions and to easily compare the results. A statistical test 24 | is used to determine whether the results truly differ.""" 25 | url { 26 | src: 27 | "https://github.com/Chris00/ocaml-benchmark/releases/download/1.6/benchmark-1.6.tbz" 28 | checksum: "md5=425d16d91e11bc81e3d347884f8fe991" 29 | } 30 | -------------------------------------------------------------------------------- /esy.lock/opam/biniou.1.2.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | 5 | homepage: "https://github.com/mjambon/biniou" 6 | bug-reports: "https://github.com/mjambon/biniou/issues" 7 | dev-repo: "git+https://github.com/mjambon/biniou.git" 8 | license: "BSD-3-Clause" 9 | 10 | build: [ 11 | ["jbuilder" "build" "-p" name "-j" jobs] 12 | ["jbuilder" "runtest" "-p" name] {with-test} 13 | ] 14 | depends: [ 15 | "ocaml" {>= "4.02.3"} 16 | "conf-which" {build} 17 | "jbuilder" {build & >= "1.0+beta7"} 18 | "easy-format" 19 | ] 20 | synopsis: 21 | "Binary data format designed for speed, safety, ease of use and backward compatibility as protocols evolve" 22 | url { 23 | src: "https://github.com/mjambon/biniou/archive/v1.2.0.tar.gz" 24 | checksum: "md5=f3e92358e832ed94eaf23ce622ccc2f9" 25 | } 26 | -------------------------------------------------------------------------------- /esy.lock/opam/cmdliner.1.0.3/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/cmdliner" 5 | doc: "http://erratique.ch/software/cmdliner/doc/Cmdliner" 6 | dev-repo: "git+http://erratique.ch/repos/cmdliner.git" 7 | bug-reports: "https://github.com/dbuenzli/cmdliner/issues" 8 | tags: [ "cli" "system" "declarative" "org:erratique" ] 9 | license: "ISC" 10 | depends:[ "ocaml" {>= "4.03.0"} ] 11 | build: [[ make "all" "PREFIX=%{prefix}%" ]] 12 | install: 13 | [[make "install" "LIBDIR=%{_:lib}%" "DOCDIR=%{_:doc}%" ] 14 | [make "install-doc" "LIBDIR=%{_:lib}%" "DOCDIR=%{_:doc}%" ]] 15 | 16 | synopsis: """Declarative definition of command line interfaces for OCaml""" 17 | description: """\ 18 | 19 | Cmdliner allows the declarative definition of command line interfaces 20 | for OCaml. 21 | 22 | It provides a simple and compositional mechanism to convert command 23 | line arguments to OCaml values and pass them to your functions. The 24 | module automatically handles syntax errors, help messages and UNIX man 25 | page generation. It supports programs with single or multiple commands 26 | and respects most of the [POSIX][1] and [GNU][2] conventions. 27 | 28 | Cmdliner has no dependencies and is distributed under the ISC license. 29 | 30 | [1]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html 31 | [2]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html 32 | """ 33 | url { 34 | archive: "http://erratique.ch/software/cmdliner/releases/cmdliner-1.0.3.tbz" 35 | checksum: "3674ad01d4445424105d33818c78fba8" 36 | } 37 | -------------------------------------------------------------------------------- /esy.lock/opam/conf-m4.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "tim@gfxmonk.net" 3 | homepage: "http://www.gnu.org/software/m4/m4.html" 4 | bug-reports: "https://github.com/ocaml/opam-repository/issues" 5 | authors: "GNU Project" 6 | license: "GPL-3" 7 | build: [["sh" "-exc" "echo | m4"]] 8 | depexts: [ 9 | ["m4"] {os-distribution = "debian"} 10 | ["m4"] {os-distribution = "ubuntu"} 11 | ["m4"] {os-distribution = "fedora"} 12 | ["m4"] {os-distribution = "rhel"} 13 | ["m4"] {os-distribution = "centos"} 14 | ["m4"] {os-distribution = "alpine"} 15 | ["m4"] {os-distribution = "nixos"} 16 | ["m4"] {os-family = "suse"} 17 | ["m4"] {os-distribution = "oraclelinux"} 18 | ["m4"] {os-distribution = "archlinux"} 19 | ] 20 | synopsis: "Virtual package relying on m4" 21 | description: 22 | "This package can only install if the m4 binary is installed on the system." 23 | flags: conf 24 | -------------------------------------------------------------------------------- /esy.lock/opam/conf-which.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "unixjunkie@sdf.org" 3 | homepage: "http://www.gnu.org/software/which/" 4 | authors: "Carlo Wood" 5 | bug-reports: "https://github.com/ocaml/opam-repository/issues" 6 | license: "GPL-2+" 7 | build: [["which" "which"]] 8 | depexts: [ 9 | ["which"] {os-distribution = "centos"} 10 | ["which"] {os-distribution = "fedora"} 11 | ["which"] {os-family = "suse"} 12 | ["debianutils"] {os-distribution = "debian"} 13 | ["debianutils"] {os-distribution = "ubuntu"} 14 | ["which"] {os-distribution = "nixos"} 15 | ["which"] {os-distribution = "archlinux"} 16 | ] 17 | synopsis: "Virtual package relying on which" 18 | description: 19 | "This package can only install if the which program is installed on the system." 20 | flags: conf 21 | -------------------------------------------------------------------------------- /esy.lock/opam/cppo.1.6.5/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | homepage: "https://github.com/mjambon/cppo" 5 | dev-repo: "git+https://github.com/mjambon/cppo.git" 6 | bug-reports: "https://github.com/mjambon/cppo/issues" 7 | license: "BSD-3-Clause" 8 | 9 | build: [ 10 | ["jbuilder" "subst" "-p" name] {pinned} 11 | ["jbuilder" "build" "-p" name "-j" jobs] 12 | ["jbuilder" "runtest" "-p" name] {with-test} 13 | ] 14 | depends: [ 15 | "ocaml" 16 | "jbuilder" {build & >= "1.0+beta17"} 17 | "base-unix" 18 | ] 19 | synopsis: "Equivalent of the C preprocessor for OCaml programs" 20 | url { 21 | src: "https://github.com/mjambon/cppo/archive/v1.6.5.tar.gz" 22 | checksum: "md5=1cd25741d31417995b0973fe0b6f6c82" 23 | } 24 | -------------------------------------------------------------------------------- /esy.lock/opam/dune.1.8.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "opensource@janestreet.com" 3 | authors: ["Jane Street Group, LLC "] 4 | homepage: "https://github.com/ocaml/dune" 5 | bug-reports: "https://github.com/ocaml/dune/issues" 6 | dev-repo: "git+https://github.com/ocaml/dune.git" 7 | license: "MIT" 8 | depends: [ 9 | "ocaml" {>= "4.02"} 10 | "base-unix" 11 | "base-threads" 12 | ] 13 | build: [ 14 | # opam 2 sets OPAM_SWITCH_PREFIX, so we don't need a hardcoded path 15 | ["ocaml" "configure.ml" "--libdir" lib] {opam-version < "2"} 16 | ["ocaml" "bootstrap.ml"] 17 | ["./boot.exe" "--release" "--subst"] {pinned} 18 | ["./boot.exe" "--release" "-j" jobs] 19 | ] 20 | conflicts: [ 21 | "jbuilder" {!= "transition"} 22 | "odoc" {< "1.3.0"} 23 | ] 24 | 25 | synopsis: "Fast, portable and opinionated build system" 26 | description: """ 27 | dune is a build system that was designed to simplify the release of 28 | Jane Street packages. It reads metadata from "dune" files following a 29 | very simple s-expression syntax. 30 | 31 | dune is fast, it has very low-overhead and support parallel builds on 32 | all platforms. It has no system dependencies, all you need to build 33 | dune and packages using dune is OCaml. You don't need or make or bash 34 | as long as the packages themselves don't use bash explicitly. 35 | 36 | dune supports multi-package development by simply dropping multiple 37 | repositories into the same directory. 38 | 39 | It also supports multi-context builds, such as building against 40 | several opam roots/switches simultaneously. This helps maintaining 41 | packages across several versions of OCaml and gives cross-compilation 42 | for free. 43 | """ 44 | url { 45 | src: "https://github.com/ocaml/dune/releases/download/1.8.2/dune-1.8.2.tbz" 46 | checksum: "md5=2b7f45a6e14865f2318d34f12221ec1e" 47 | } 48 | -------------------------------------------------------------------------------- /esy.lock/opam/easy-format.1.3.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | homepage: "http://mjambon.com/easy-format.html" 5 | bug-reports: "https://github.com/mjambon/easy-format/issues" 6 | dev-repo: "git+https://github.com/mjambon/easy-format.git" 7 | build: [ 8 | ["jbuilder" "build" "-p" name "-j" jobs] 9 | ["jbuilder" "runtest" "-p" name] {with-test} 10 | ] 11 | depends: [ 12 | "ocaml" {>= "4.02.3"} 13 | "jbuilder" {build} 14 | ] 15 | synopsis: 16 | "High-level and functional interface to the Format module of the OCaml standard library" 17 | url { 18 | src: "https://github.com/mjambon/easy-format/archive/v1.3.1.tar.gz" 19 | checksum: "md5=4e163700fb88fdcd6b8976c3a216c8ea" 20 | } 21 | -------------------------------------------------------------------------------- /esy.lock/opam/fmt.0.8.5/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: [ 4 | "Daniel Bünzli " 5 | "Gabriel Radanne" 6 | ] 7 | homepage: "http://erratique.ch/software/fmt" 8 | doc: "http://erratique.ch/software/fmt" 9 | dev-repo: "git+http://erratique.ch/repos/fmt.git" 10 | bug-reports: "https://github.com/dbuenzli/fmt/issues" 11 | tags: [ "string" "format" "pretty-print" "org:erratique" ] 12 | license: "ISC" 13 | depends: [ 14 | "ocaml" {>= "4.01.0"} 15 | "ocamlfind" {build} 16 | "ocamlbuild" {build} 17 | "topkg" {build & >= "0.9.0"} 18 | "result" 19 | "uchar" 20 | ] 21 | depopts: [ "base-unix" "cmdliner" ] 22 | conflicts: [ "cmdliner" {< "0.9.8"} ] 23 | build: [[ 24 | "ocaml" "pkg/pkg.ml" "build" 25 | "--dev-pkg" "%{pinned}%" 26 | "--with-base-unix" "%{base-unix:installed}%" 27 | "--with-cmdliner" "%{cmdliner:installed}%" ]] 28 | synopsis: "OCaml Format pretty-printer combinators" 29 | description: """ 30 | Fmt exposes combinators to devise `Format` pretty-printing functions. 31 | 32 | Fmt depends only on the OCaml standard library. The optional `Fmt_tty` 33 | library that allows to setup formatters for terminal color output 34 | depends on the Unix library. The optional `Fmt_cli` library that 35 | provides command line support for Fmt depends on [`Cmdliner`][cmdliner]. 36 | 37 | Fmt is distributed under the ISC license. 38 | 39 | [cmdliner]: http://erratique.ch/software/cmdliner""" 40 | url { 41 | src: "http://erratique.ch/software/fmt/releases/fmt-0.8.5.tbz" 42 | checksum: "md5=77b64aa6f20f09de28f2405d6195f12c" 43 | } 44 | -------------------------------------------------------------------------------- /esy.lock/opam/fpath.0.7.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/fpath" 5 | doc: "http://erratique.ch/software/fpath/doc" 6 | dev-repo: "git+http://erratique.ch/repos/fpath.git" 7 | bug-reports: "https://github.com/dbuenzli/fpath/issues" 8 | tags: [ "file" "system" "path" "org:erratique" ] 9 | license: "ISC" 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {build} 14 | "topkg" {build & >= "0.9.0"} 15 | "result" 16 | "astring" 17 | ] 18 | build: [[ 19 | "ocaml" "pkg/pkg.ml" "build" 20 | "--dev-pkg" "%{pinned}%" ]] 21 | synopsis: "File system paths for OCaml" 22 | description: """ 23 | Fpath is an OCaml module for handling file system paths with POSIX or 24 | Windows conventions. Fpath processes paths without accessing the file 25 | system and is independent from any system library. 26 | 27 | Fpath depends on [Astring][astring] and is distributed under the ISC 28 | license. 29 | 30 | [astring]: http://erratique.ch/software/astring""" 31 | url { 32 | src: "http://erratique.ch/software/fpath/releases/fpath-0.7.2.tbz" 33 | checksum: "md5=52c7ecb0bf180088336f3c645875fa41" 34 | } 35 | -------------------------------------------------------------------------------- /esy.lock/opam/jbuilder.transition/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "opensource@janestreet.com" 3 | authors: ["Jane Street Group, LLC "] 4 | homepage: "https://github.com/ocaml/dune" 5 | bug-reports: "https://github.com/ocaml/dune/issues" 6 | dev-repo: "git+https://github.com/ocaml/dune.git" 7 | license: "MIT" 8 | depends: ["ocaml" "dune"] 9 | post-messages: [ 10 | "Jbuilder has been renamed and the jbuilder package is now a transition \ 11 | package. Use the dune package instead." 12 | ] 13 | synopsis: 14 | "This is a transition package, jbuilder is now named dune. Use the dune" 15 | description: "package instead." 16 | -------------------------------------------------------------------------------- /esy.lock/opam/logs.0.6.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/logs" 5 | doc: "http://erratique.ch/software/logs/doc" 6 | dev-repo: "git+http://erratique.ch/repos/logs.git" 7 | bug-reports: "https://github.com/dbuenzli/logs/issues" 8 | tags: [ "log" "system" "org:erratique" ] 9 | license: "ISC" 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {build} 14 | "topkg" {build} 15 | "result" 16 | "mtime" {with-test} 17 | ] 18 | depopts: [ 19 | "js_of_ocaml" 20 | "fmt" 21 | "cmdliner" 22 | "lwt" ] 23 | conflicts: [ "cmdliner" {< "0.9.8"} ] 24 | build: [[ 25 | "ocaml" "pkg/pkg.ml" "build" 26 | "--pinned" "%{pinned}%" 27 | "--with-js_of_ocaml" "%{js_of_ocaml:installed}%" 28 | "--with-fmt" "%{fmt:installed}%" 29 | "--with-cmdliner" "%{cmdliner:installed}%" 30 | "--with-lwt" "%{lwt:installed}%" ]] 31 | synopsis: "Logging infrastructure for OCaml" 32 | description: """ 33 | Logs provides a logging infrastructure for OCaml. Logging is performed 34 | on sources whose reporting level can be set independently. Log message 35 | report is decoupled from logging and is handled by a reporter. 36 | 37 | A few optional log reporters are distributed with the base library and 38 | the API easily allows to implement your own. 39 | 40 | `Logs` depends only on the `result` compatibility package. The 41 | optional `Logs_fmt` reporter on OCaml formatters depends on [Fmt][fmt]. 42 | The optional `Logs_browser` reporter that reports to the web browser 43 | console depends on [js_of_ocaml][jsoo]. The optional `Logs_cli` library 44 | that provides command line support for controlling Logs depends on 45 | [`Cmdliner`][cmdliner]. The optional `Logs_lwt` library that provides Lwt logging 46 | functions depends on [`Lwt`][lwt] 47 | 48 | Logs and its reporters are distributed under the ISC license. 49 | 50 | [fmt]: http://erratique.ch/software/fmt 51 | [jsoo]: http://ocsigen.org/js_of_ocaml/ 52 | [cmdliner]: http://erratique.ch/software/cmdliner 53 | [lwt]: http://ocsigen.org/lwt/""" 54 | url { 55 | src: "http://erratique.ch/software/logs/releases/logs-0.6.2.tbz" 56 | checksum: "md5=19f824c02c83c6dddc3bfb6459e4743e" 57 | } 58 | -------------------------------------------------------------------------------- /esy.lock/opam/lwt.4.1.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | version: "4.1.0" 3 | maintainer: [ 4 | "Anton Bachin " 5 | "Mauricio Fernandez " 6 | "Simon Cruanes " 7 | ] 8 | authors: [ 9 | "Jérôme Vouillon" 10 | "Jérémie Dimino" 11 | ] 12 | homepage: "https://github.com/ocsigen/lwt" 13 | doc: "https://ocsigen.org/lwt/manual/" 14 | bug-reports: "https://github.com/ocsigen/lwt/issues" 15 | license: "LGPL with OpenSSL linking exception" 16 | dev-repo: "git+https://github.com/ocsigen/lwt.git" 17 | build: [ 18 | [ "ocaml" "src/util/configure.ml" "-use-libev" "%{conf-libev:installed}%" ] 19 | [ "jbuilder" "build" "-p" name "-j" jobs ] 20 | ] 21 | 22 | depends: [ 23 | "ocaml" {>= "4.02.0"} 24 | "cppo" {build & >= "1.1.0"} 25 | "jbuilder" {build & >= "1.0+beta14"} 26 | "ocamlfind" {build & >= "1.7.3-1"} 27 | "result" 28 | ] 29 | depopts: [ 30 | "base-threads" 31 | "base-unix" 32 | "conf-libev" 33 | ] 34 | # In practice, Lwt requires OCaml >= 4.02.3, as that is a constraint of the 35 | # dependency jbuilder. 36 | messages: [ 37 | "For the PPX, please install package lwt_ppx" 38 | {!lwt_ppx:installed} 39 | "For the Camlp4 syntax, please install package lwt_camlp4" 40 | {camlp4:installed & !lwt_camlp4:installed} 41 | "For Lwt_log and Lwt_daemon, please install package lwt_log" 42 | {!lwt_log:installed} 43 | ] 44 | synopsis: "Promises, concurrency, and parallelized I/O" 45 | description: """ 46 | A promise is a value that may become determined in the future. 47 | 48 | Lwt provides typed, composable promises. Promises that are resolved by I/O are 49 | resolved by Lwt in parallel. 50 | 51 | Meanwhile, OCaml code, including code creating and waiting on promises, runs in 52 | a single thread by default. This reduces the need for locks or other 53 | synchronization primitives. Code can be run in parallel on an opt-in basis.""" 54 | conflicts: [ 55 | "ocaml-variants" {= "4.02.1+BER"} 56 | ] 57 | url { 58 | src: "https://github.com/ocsigen/lwt/archive/4.1.0.tar.gz" 59 | checksum: "md5=e919bee206f18b3d49250ecf9584fde7" 60 | } 61 | -------------------------------------------------------------------------------- /esy.lock/opam/menhir.20181113/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | "Yann Régis-Gianas " 6 | ] 7 | homepage: "http://gitlab.inria.fr/fpottier/menhir" 8 | dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git" 9 | bug-reports: "menhir@inria.fr" 10 | build: [ 11 | [make "-f" "Makefile" "PREFIX=%{prefix}%" "USE_OCAMLFIND=true" "docdir=%{doc}%/menhir" "libdir=%{lib}%/menhir" "mandir=%{man}%/man1"] 12 | ] 13 | install: [ 14 | [make "-f" "Makefile" "install" "PREFIX=%{prefix}%" "docdir=%{doc}%/menhir" "libdir=%{lib}%/menhir" "mandir=%{man}%/man1"] 15 | ] 16 | remove: [ 17 | [make "-f" "Makefile" "uninstall" "PREFIX=%{prefix}%" "docdir=%{doc}%/menhir" "libdir=%{lib}%/menhir" "mandir=%{man}%/man1"] 18 | ] 19 | depends: [ 20 | "ocaml" {>= "4.02"} 21 | "ocamlfind" {build} 22 | "ocamlbuild" {build} 23 | ] 24 | synopsis: "An LR(1) parser generator" 25 | url { 26 | src: 27 | "https://gitlab.inria.fr/fpottier/menhir/repository/20181113/archive.tar.gz" 28 | checksum: [ 29 | "md5=69ce441a06ea131cd43e7b44c4303f3c" 30 | "sha512=4ddefcd71d305bfb933a4056da57e36c13c99ec6dfcc4695814798fbbd78b4d65828381ebcb0e58c4c0394105ac763af3d475474e05e408f7080315bc3cf6176" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /esy.lock/opam/merlin-extend.0.3/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Frederic Bour " 3 | authors: "Frederic Bour " 4 | homepage: "https://github.com/let-def/merlin-extend" 5 | bug-reports: "https://github.com/let-def/merlin-extend" 6 | license: "MIT" 7 | dev-repo: "git+https://github.com/let-def/merlin-extend.git" 8 | build: [make] 9 | install: [make "install"] 10 | remove: ["ocamlfind" "remove" "merlin_extend"] 11 | depends: [ 12 | "ocaml" {>= "4.02.3"} 13 | "ocamlfind" {build} 14 | "cppo" {build} 15 | ] 16 | synopsis: "A protocol to provide custom frontend to Merlin" 17 | description: """ 18 | This protocol allows to replace the OCaml frontend of Merlin. 19 | It extends what used to be done with the `-pp' flag to handle a few more cases.""" 20 | flags: light-uninstall 21 | url { 22 | src: "https://github.com/let-def/merlin-extend/archive/v0.3.tar.gz" 23 | checksum: "md5=9c6dfd4f53328f02f12fcc265f4e2dda" 24 | } 25 | -------------------------------------------------------------------------------- /esy.lock/opam/merlin.3.2.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | name: "merlin" 3 | synopsis: "Installation with Opam" 4 | description: """ 5 | If you have a working [Opam](https://opam.ocaml.org/) installation, Merlin is only two commands away: 6 | 7 | ```shell 8 | opam install merlin 9 | opam user-setup install 10 | ``` 11 | 12 | [opam-user-setup](https://github.com/OCamlPro/opam-user-setup) takes care of configuring Emacs and Vim to make best use of your current install. 13 | 14 | You can also [configure the editor](#editor-setup) yourself, if you prefer.""" 15 | maintainer: "defree@gmail.com" 16 | authors: "The Merlin team" 17 | homepage: "https://github.com/ocaml/merlin" 18 | bug-reports: "https://github.com/ocaml/merlin/issues" 19 | depends: [ 20 | "ocaml" {>= "4.02.1" & < "4.08"} 21 | "dune" {build} 22 | "ocamlfind" {>= "1.5.2"} 23 | "yojson" 24 | "craml" {with-test} 25 | ] 26 | build: [ 27 | ["dune" "subst"] {pinned} 28 | ["dune" "build" "-p" name "-j" jobs] 29 | ] 30 | post-messages: 31 | """ 32 | merlin installed. 33 | 34 | Quick setup for VIM 35 | ------------------- 36 | Append this to your .vimrc to add merlin to vim's runtime-path: 37 | let g:opamshare = substitute(system('opam config var share'),'\\n$','','''') 38 | execute "set rtp+=" . g:opamshare . "/merlin/vim" 39 | 40 | Also run the following line in vim to index the documentation: 41 | :execute "helptags " . g:opamshare . "/merlin/vim/doc" 42 | 43 | Quick setup for EMACS 44 | ------------------- 45 | Add opam emacs directory to your load-path by appending this to your .emacs: 46 | (let ((opam-share (ignore-errors (car (process-lines "opam" "config" "var" "share"))))) 47 | (when (and opam-share (file-directory-p opam-share)) 48 | ;; Register Merlin 49 | (add-to-list 'load-path (expand-file-name "emacs/site-lisp" opam-share)) 50 | (autoload 'merlin-mode "merlin" nil t nil) 51 | ;; Automatically start it in OCaml buffers 52 | (add-hook 'tuareg-mode-hook 'merlin-mode t) 53 | (add-hook 'caml-mode-hook 'merlin-mode t) 54 | ;; Use opam switch to lookup ocamlmerlin binary 55 | (setq merlin-command 'opam))) 56 | 57 | Take a look at https://github.com/ocaml/merlin for more information 58 | 59 | Quick setup with opam-user-setup 60 | -------------------------------- 61 | 62 | Opam-user-setup support Merlin. 63 | 64 | $ opam user-setup install 65 | 66 | should take care of basic setup. 67 | See https://github.com/OCamlPro/opam-user-setup""" 68 | {success & !user-setup:installed} 69 | dev-repo: "git+https://github.com/ocaml/merlin.git" 70 | url { 71 | src: 72 | "https://github.com/ocaml/merlin/releases/download/v3.2.2/merlin-v3.2.2.tbz" 73 | checksum: "md5=ede35b65f8ac9c440cfade5445662c54" 74 | } 75 | -------------------------------------------------------------------------------- /esy.lock/opam/ocaml-migrate-parsetree.1.2.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "frederic.bour@lakaban.net" 3 | authors: [ 4 | "Frédéric Bour " 5 | "Jérémie Dimino " 6 | ] 7 | license: "LGPL-2.1" 8 | homepage: "https://github.com/ocaml-ppx/ocaml-migrate-parsetree" 9 | bug-reports: "https://github.com/ocaml-ppx/ocaml-migrate-parsetree/issues" 10 | dev-repo: "git+https://github.com/ocaml-ppx/ocaml-migrate-parsetree.git" 11 | doc: "https://ocaml-ppx.github.io/ocaml-migrate-parsetree/" 12 | tags: [ "syntax" "org:ocamllabs" ] 13 | build: [ 14 | ["dune" "build" "-p" name "-j" jobs] 15 | ] 16 | depends: [ 17 | "result" 18 | "ppx_derivers" 19 | "dune" {build & >= "1.6.0"} 20 | "ocaml" {>= "4.02.3"} 21 | ] 22 | synopsis: "Convert OCaml parsetrees between different versions" 23 | description: """ 24 | Convert OCaml parsetrees between different versions 25 | 26 | This library converts parsetrees, outcometree and ast mappers between 27 | different OCaml versions. High-level functions help making PPX 28 | rewriters independent of a compiler version. 29 | """ 30 | url { 31 | src: 32 | "https://github.com/ocaml-ppx/ocaml-migrate-parsetree/releases/download/v1.2.0/ocaml-migrate-parsetree-v1.2.0.tbz" 33 | checksum: "md5=cc6fb09ad6f99156c7dba47711c62c6f" 34 | } 35 | -------------------------------------------------------------------------------- /esy.lock/opam/ocamlbuild.0.14.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Gabriel Scherer " 3 | authors: ["Nicolas Pouillard" "Berke Durak"] 4 | homepage: "https://github.com/ocaml/ocamlbuild/" 5 | bug-reports: "https://github.com/ocaml/ocamlbuild/issues" 6 | license: "LGPL-2 with OCaml linking exception" 7 | doc: "https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc" 8 | dev-repo: "git+https://github.com/ocaml/ocamlbuild.git" 9 | build: [ 10 | [ 11 | make 12 | "-f" 13 | "configure.make" 14 | "all" 15 | "OCAMLBUILD_PREFIX=%{prefix}%" 16 | "OCAMLBUILD_BINDIR=%{bin}%" 17 | "OCAMLBUILD_LIBDIR=%{lib}%" 18 | "OCAMLBUILD_MANDIR=%{man}%" 19 | "OCAML_NATIVE=%{ocaml:native}%" 20 | "OCAML_NATIVE_TOOLS=%{ocaml:native}%" 21 | ] 22 | [make "check-if-preinstalled" "all" "opam-install"] 23 | ] 24 | conflicts: [ 25 | "base-ocamlbuild" 26 | "ocamlfind" {< "1.6.2"} 27 | ] 28 | synopsis: 29 | "OCamlbuild is a build system with builtin rules to easily build most OCaml projects." 30 | depends: [ 31 | "ocaml" {>= "4.03"} 32 | ] 33 | url { 34 | src: "https://github.com/ocaml/ocamlbuild/archive/0.14.0.tar.gz" 35 | checksum: "sha256=87b29ce96958096c0a1a8eeafeb6268077b2d11e1bf2b3de0f5ebc9cf8d42e78" 36 | } 37 | -------------------------------------------------------------------------------- /esy.lock/opam/ocamlfind.1.8.0/files/ocaml-stub: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BINDIR=$(dirname "$(command -v ocamlc)") 4 | "$BINDIR/ocaml" -I "$OCAML_TOPLEVEL_PATH" "$@" 5 | -------------------------------------------------------------------------------- /esy.lock/opam/ocamlfind.1.8.0/files/ocamlfind.install: -------------------------------------------------------------------------------- 1 | bin: [ 2 | "src/findlib/ocamlfind" {"ocamlfind"} 3 | "?src/findlib/ocamlfind_opt" {"ocamlfind"} 4 | "?tools/safe_camlp4" 5 | ] 6 | toplevel: ["src/findlib/topfind"] 7 | -------------------------------------------------------------------------------- /esy.lock/opam/ocamlfind.1.8.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Thomas Gazagnaire " 3 | homepage: "http://projects.camlcity.org/projects/findlib.html" 4 | bug-reports: "https://gitlab.camlcity.org/gerd/lib-findlib/issues" 5 | dev-repo: "git+https://gitlab.camlcity.org/gerd/lib-findlib.git" 6 | build: [ 7 | [ 8 | "./configure" 9 | "-bindir" 10 | bin 11 | "-sitelib" 12 | lib 13 | "-mandir" 14 | man 15 | "-config" 16 | "%{lib}%/findlib.conf" 17 | "-no-custom" 18 | "-no-topfind" {ocaml:preinstalled} 19 | ] 20 | [make "all"] 21 | [make "opt"] {ocaml:native} 22 | ] 23 | install: [ 24 | [make "install"] 25 | ["install" "-m" "0755" "ocaml-stub" "%{bin}%/ocaml"] {ocaml:preinstalled} 26 | ] 27 | remove: [ 28 | ["ocamlfind" "remove" "bytes"] 29 | [ 30 | "./configure" 31 | "-bindir" 32 | bin 33 | "-sitelib" 34 | lib 35 | "-mandir" 36 | man 37 | "-config" 38 | "%{lib}%/findlib.conf" 39 | "-no-topfind" {ocaml:preinstalled} 40 | ] 41 | [make "uninstall"] 42 | ["rm" "-f" "%{bin}%/ocaml"] {ocaml:preinstalled} 43 | ] 44 | depends: [ 45 | "ocaml" {>= "4.00.0"} 46 | "conf-m4" {build} 47 | ] 48 | synopsis: "A library manager for OCaml" 49 | description: """ 50 | Findlib is a library manager for OCaml. It provides a convention how 51 | to store libraries, and a file format ("META") to describe the 52 | properties of libraries. There is also a tool (ocamlfind) for 53 | interpreting the META files, so that it is very easy to use libraries 54 | in programs and scripts.""" 55 | authors: "Gerd Stolpmann " 56 | extra-files: [ 57 | ["ocamlfind.install" "md5=06f2c282ab52d93aa6adeeadd82a2543"] 58 | ["ocaml-stub" "md5=181f259c9e0bad9ef523e7d4abfdf87a"] 59 | ] 60 | url { 61 | src: "http://download.camlcity.org/download/findlib-1.8.0.tar.gz" 62 | checksum: "md5=a710c559667672077a93d34eb6a42e5b" 63 | mirrors: "http://download2.camlcity.org/download/findlib-1.8.0.tar.gz" 64 | } 65 | -------------------------------------------------------------------------------- /esy.lock/opam/odoc.1.4.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | 3 | homepage: "http://github.com/ocaml/odoc" 4 | doc: "https://github.com/ocaml/odoc#readme" 5 | bug-reports: "https://github.com/ocaml/odoc/issues" 6 | license: "ISC" 7 | 8 | authors: [ 9 | "Thomas Refis " 10 | "David Sheets " 11 | "Leo White " 12 | ] 13 | maintainer: "Anton Bachin " 14 | dev-repo: "git+https://github.com/ocaml/odoc.git" 15 | 16 | synopsis: "OCaml documentation generator" 17 | 18 | depends: [ 19 | "astring" {build} 20 | "cmdliner" {build & >= "1.0.0"} 21 | "cppo" {build} 22 | "dune" {build} 23 | "fpath" {build} 24 | "ocaml" {>= "4.02.0"} 25 | "result" {build} 26 | "tyxml" {build & >= "4.3.0"} 27 | 28 | "alcotest" {dev & >= "0.8.3"} 29 | "markup" {dev & >= "0.8.0"} 30 | "ocamlfind" {dev} 31 | "sexplib" {dev & >= "113.33.00"} 32 | 33 | "bisect_ppx" {with-test & >= "1.3.0"} 34 | ] 35 | 36 | build: [ 37 | ["dune" "subst"] {pinned} 38 | ["dune" "build" "-p" name "-j" jobs] 39 | ] 40 | 41 | url { 42 | src: "https://github.com/ocaml/odoc/archive/1.4.0.tar.gz" 43 | checksum: "md5=8fec61a88813b2295a16298fc6daedf1" 44 | } 45 | -------------------------------------------------------------------------------- /esy.lock/opam/ounit.2.0.8/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | authors: [ "Maas-Maarten Zeeman" "Sylvain Le Gall" ] 3 | maintainer: "https://github.com/ocaml/opam-repository/issues" 4 | homepage: "http://ounit.forge.ocamlcore.org" 5 | bug-reports: "https://forge.ocamlcore.org/tracker/?func=browse&group_id=162&atid=730" 6 | dev-repo: "git+https://github.com/gildor478/ounit.git" 7 | doc: ["http://ounit.forge.ocamlcore.org/api-ounit/index.html"] 8 | build: [make "build"] 9 | remove: [["ocamlfind" "remove" "oUnit"]] 10 | depends: [ 11 | "ocaml" {>= "3.11.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {build} 14 | "base-bytes" 15 | ] 16 | install: [make "install"] 17 | synopsis: 18 | "Unit testing framework loosely based on HUnit. It is similar to JUnit, and other XUnit testing frameworks" 19 | flags: light-uninstall 20 | url { 21 | src: "https://download.ocamlcore.org/ounit/ounit/2.0.8/ounit-2.0.8.tar.gz" 22 | checksum: "md5=bd12d66c9dbd95a50570bb686b0f10f5" 23 | } 24 | -------------------------------------------------------------------------------- /esy.lock/opam/ppx_derivers.1.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "jeremie@dimino.org" 3 | authors: ["Jérémie Dimino"] 4 | license: "BSD3" 5 | homepage: "https://github.com/ocaml-ppx/ppx_derivers" 6 | bug-reports: "https://github.com/ocaml-ppx/ppx_derivers/issues" 7 | dev-repo: "git://github.com/ocaml-ppx/ppx_derivers.git" 8 | build: [ 9 | ["jbuilder" "build" "-p" name "-j" jobs] 10 | ] 11 | depends: [ 12 | "ocaml" 13 | "jbuilder" {build & >= "1.0+beta7"} 14 | ] 15 | synopsis: "Shared [@@deriving] plugin registry" 16 | description: """ 17 | Ppx_derivers is a tiny package whose sole purpose is to allow 18 | ppx_deriving and ppx_type_conv to inter-operate gracefully when linked 19 | as part of the same ocaml-migrate-parsetree driver.""" 20 | url { 21 | src: "https://github.com/ocaml-ppx/ppx_derivers/archive/1.0.tar.gz" 22 | checksum: "md5=4ddce8f43fdb9b0ef0ab6a7cbfebc3e3" 23 | } 24 | -------------------------------------------------------------------------------- /esy.lock/opam/qcheck-alcotest.0.9/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "simon.cruanes.2007@m4x.org" 3 | authors: "Simon Cruanes " 4 | tags: ["test" "property" "quickcheck"] 5 | homepage: "https://github.com/c-cube/qcheck/" 6 | doc: "http://c-cube.github.io/qcheck/" 7 | bug-reports: "https://github.com/c-cube/qcheck/issues" 8 | depends: [ 9 | "dune" {build} 10 | "ocaml" {>= "4.03.0"} 11 | "base-bytes" 12 | "base-unix" 13 | "qcheck-core" {>= "0.9"} 14 | "alcotest" {>= "0.8.0"} 15 | "odoc" {doc} 16 | ] 17 | build:[ 18 | ["dune" "build" "-p" name "-j" jobs] 19 | ["dune" "runtest" "-p" name] {with-test} 20 | ["dune" "build" "@doc" "-p" name] {with-doc} 21 | ] 22 | dev-repo: "git+https://github.com/c-cube/qcheck.git" 23 | synopsis: "QuickCheck inspired property-based testing for OCaml." 24 | description: """ 25 | This module provides QCheck integration with alcotest.""" 26 | url { 27 | src: "https://github.com/c-cube/qcheck/archive/0.9.tar.gz" 28 | checksum: [ 29 | "md5=7782c8cfce30a5fb766d933e99129ee7" 30 | "sha512=e1007b4a3be338406d855efcf8d13ac4961963a6c77b794ab83973950e21c777cb66ab6020a0a714f96866597bc8bf7a76a84243e5062dab5b41978e78422e0b" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /esy.lock/opam/qcheck-core.0.9/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "simon.cruanes.2007@m4x.org" 3 | authors: "Simon Cruanes " 4 | tags: ["test" "property" "quickcheck"] 5 | homepage: "https://github.com/c-cube/qcheck/" 6 | doc: "http://c-cube.github.io/qcheck/" 7 | bug-reports: "https://github.com/c-cube/qcheck/issues" 8 | depends: [ 9 | "dune" {build} 10 | "ocaml" {>= "4.03.0"} 11 | "base-bytes" 12 | "base-unix" 13 | "odoc" {doc} 14 | ] 15 | conflicts: [ 16 | "ounit" {< "2.0"} 17 | ] 18 | build: [ 19 | ["dune" "build" "-p" name "-j" jobs] 20 | ["dune" "runtest" "-p" name] {with-test} 21 | ["dune" "build" "@doc" "-p" name] {with-doc} 22 | ] 23 | dev-repo: "git+https://github.com/c-cube/qcheck.git" 24 | synopsis: "QuickCheck inspired property-based testing for OCaml." 25 | description: """ 26 | This module allows to check invariants (properties of some types) over 27 | randomly generated instances of the type. It provides combinators for 28 | generating instances and printing them.""" 29 | url { 30 | src: "https://github.com/c-cube/qcheck/archive/0.9.tar.gz" 31 | checksum: [ 32 | "md5=7782c8cfce30a5fb766d933e99129ee7" 33 | "sha512=e1007b4a3be338406d855efcf8d13ac4961963a6c77b794ab83973950e21c777cb66ab6020a0a714f96866597bc8bf7a76a84243e5062dab5b41978e78422e0b" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /esy.lock/opam/qcheck-ounit.0.9/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "simon.cruanes.2007@m4x.org" 3 | authors: "Simon Cruanes " 4 | tags: ["test" "property" "quickcheck"] 5 | homepage: "https://github.com/c-cube/qcheck/" 6 | doc: "http://c-cube.github.io/qcheck/" 7 | bug-reports: "https://github.com/c-cube/qcheck/issues" 8 | depends: [ 9 | "dune" {build} 10 | "ocaml" {>= "4.03.0"} 11 | "base-bytes" 12 | "base-unix" 13 | "qcheck-core" {>= "0.9"} 14 | "ounit" {>= "2.0"} 15 | "odoc" {doc} 16 | ] 17 | build: [ 18 | ["dune" "build" "-p" name "-j" jobs] 19 | ["dune" "runtest" "-p" name] {with-test} 20 | ["dune" "build" "@doc" "-p" name] {with-doc} 21 | ] 22 | dev-repo: "git+https://github.com/c-cube/qcheck.git" 23 | synopsis: "QuickCheck inspired property-based testing for OCaml." 24 | description: """ 25 | This module provides QCheck integration with OUnit.""" 26 | url { 27 | src: "https://github.com/c-cube/qcheck/archive/0.9.tar.gz" 28 | checksum: [ 29 | "md5=7782c8cfce30a5fb766d933e99129ee7" 30 | "sha512=e1007b4a3be338406d855efcf8d13ac4961963a6c77b794ab83973950e21c777cb66ab6020a0a714f96866597bc8bf7a76a84243e5062dab5b41978e78422e0b" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /esy.lock/opam/qcheck.0.9/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "simon.cruanes.2007@m4x.org" 3 | authors: "Simon Cruanes " 4 | tags: ["test" "property" "quickcheck"] 5 | homepage: "https://github.com/c-cube/qcheck/" 6 | doc: "http://c-cube.github.io/qcheck/" 7 | bug-reports: "https://github.com/c-cube/qcheck/issues" 8 | depends: [ 9 | "dune" {build} 10 | "ocaml" {>= "4.03.0"} 11 | "base-bytes" 12 | "base-unix" 13 | "qcheck-core" {>= "0.9"} 14 | "qcheck-ounit" {>= "0.9"} 15 | "odoc" {doc} 16 | ] 17 | conflicts: [ 18 | "ounit" {< "2.0"} 19 | ] 20 | build: [ 21 | ["dune" "build" "-p" name "-j" jobs] 22 | ["dune" "runtest" "-p" name] {with-test} 23 | ["dune" "build" "@doc" "-p" name] {with-doc} 24 | ] 25 | dev-repo: "git+https://github.com/c-cube/qcheck.git" 26 | synopsis: "QuickCheck inspired property-based testing for OCaml." 27 | description: """ 28 | This module allows to check invariants (properties of some types) over 29 | randomly generated instances of the type. It provides combinators for 30 | generating instances and printing them.""" 31 | url { 32 | src: "https://github.com/c-cube/qcheck/archive/0.9.tar.gz" 33 | checksum: [ 34 | "md5=7782c8cfce30a5fb766d933e99129ee7" 35 | "sha512=e1007b4a3be338406d855efcf8d13ac4961963a6c77b794ab83973950e21c777cb66ab6020a0a714f96866597bc8bf7a76a84243e5062dab5b41978e78422e0b" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /esy.lock/opam/re.1.8.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "rudi.grinberg@gmail.com" 3 | authors: [ 4 | "Jerome Vouillon" 5 | "Thomas Gazagnaire" 6 | "Anil Madhavapeddy" 7 | "Rudi Grinberg" 8 | "Gabriel Radanne" 9 | ] 10 | license: "LGPL-2.0 with OCaml linking exception" 11 | homepage: "https://github.com/ocaml/ocaml-re" 12 | bug-reports: "https://github.com/ocaml/ocaml-re/issues" 13 | dev-repo: "git+https://github.com/ocaml/ocaml-re.git" 14 | build: [ 15 | ["jbuilder" "subst" "-n" name] {pinned} 16 | ["jbuilder" "build" "-p" name "-j" jobs] 17 | ["jbuilder" "runtest" "-p" name "-j" jobs] {with-test} 18 | ] 19 | depends: [ 20 | "ocaml" {>= "4.02.3"} 21 | "jbuilder" {build & >= "1.0+beta10"} 22 | "ounit" {with-test} 23 | "seq" 24 | ] 25 | synopsis: "RE is a regular expression library for OCaml" 26 | description: """ 27 | Pure OCaml regular expressions with: 28 | * Perl-style regular expressions (module Re.Perl) 29 | * Posix extended regular expressions (module Re.Posix) 30 | * Emacs-style regular expressions (module Re.Emacs) 31 | * Shell-style file globbing (module Re.Glob) 32 | * Compatibility layer for OCaml's built-in Str module (module Re.Str)""" 33 | url { 34 | src: 35 | "https://github.com/ocaml/ocaml-re/releases/download/1.8.0/re-1.8.0.tbz" 36 | checksum: "md5=765f6f8d3e6ab200866e719ed7e5178d" 37 | } 38 | -------------------------------------------------------------------------------- /esy.lock/opam/result.1.3/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "opensource@janestreet.com" 3 | authors: ["Jane Street Group, LLC "] 4 | homepage: "https://github.com/janestreet/result" 5 | dev-repo: "git+https://github.com/janestreet/result.git" 6 | bug-reports: "https://github.com/janestreet/result/issues" 7 | license: "BSD3" 8 | build: [["jbuilder" "build" "-p" name "-j" jobs]] 9 | depends: [ 10 | "ocaml" 11 | "jbuilder" {build & >= "1.0+beta11"} 12 | ] 13 | synopsis: "Compatibility Result module" 14 | description: """ 15 | Projects that want to use the new result type defined in OCaml >= 4.03 16 | while staying compatible with older version of OCaml should use the 17 | Result module defined in this library.""" 18 | url { 19 | src: 20 | "https://github.com/janestreet/result/releases/download/1.3/result-1.3.tbz" 21 | checksum: "md5=4beebefd41f7f899b6eeba7414e7ae01" 22 | } 23 | -------------------------------------------------------------------------------- /esy.lock/opam/seq.base/files/META.seq: -------------------------------------------------------------------------------- 1 | name="seq" 2 | version="[distributed with OCaml 4.07 or above]" 3 | description="dummy backward-compatibility package for iterators" 4 | requires="" 5 | -------------------------------------------------------------------------------- /esy.lock/opam/seq.base/files/seq.install: -------------------------------------------------------------------------------- 1 | lib:[ 2 | "META.seq" {"META"} 3 | ] 4 | -------------------------------------------------------------------------------- /esy.lock/opam/seq.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: " " 3 | authors: " " 4 | homepage: " " 5 | depends: [ 6 | "ocaml" {>= "4.07.0"} 7 | ] 8 | dev-repo: "git+https://github.com/ocaml/ocaml.git" 9 | bug-reports: "https://caml.inria.fr/mantis/main_page.php" 10 | synopsis: 11 | "Compatibility package for OCaml's standard iterator type starting from 4.07." 12 | extra-files: [ 13 | ["seq.install" "md5=026b31e1df290373198373d5aaa26e42"] 14 | ["META.seq" "md5=b33c8a1a6c7ed797816ce27df4855107"] 15 | ] 16 | -------------------------------------------------------------------------------- /esy.lock/opam/topkg.1.0.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/topkg" 5 | doc: "http://erratique.ch/software/topkg/doc" 6 | license: "ISC" 7 | dev-repo: "git+http://erratique.ch/repos/topkg.git" 8 | bug-reports: "https://github.com/dbuenzli/topkg/issues" 9 | tags: ["packaging" "ocamlbuild" "org:erratique"] 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build & >= "1.6.1"} 13 | "ocamlbuild" 14 | "result" ] 15 | build: [[ 16 | "ocaml" "pkg/pkg.ml" "build" 17 | "--pkg-name" name 18 | "--dev-pkg" "%{pinned}%" ]] 19 | synopsis: """The transitory OCaml software packager""" 20 | description: """\ 21 | 22 | Topkg is a packager for distributing OCaml software. It provides an 23 | API to describe the files a package installs in a given build 24 | configuration and to specify information about the package's 25 | distribution, creation and publication procedures. 26 | 27 | The optional topkg-care package provides the `topkg` command line tool 28 | which helps with various aspects of a package's life cycle: creating 29 | and linting a distribution, releasing it on the WWW, publish its 30 | documentation, add it to the OCaml opam repository, etc. 31 | 32 | Topkg is distributed under the ISC license and has **no** 33 | dependencies. This is what your packages will need as a *build* 34 | dependency. 35 | 36 | Topkg-care is distributed under the ISC license it depends on 37 | [fmt][fmt], [logs][logs], [bos][bos], [cmdliner][cmdliner], 38 | [webbrowser][webbrowser] and `opam-format`. 39 | 40 | [fmt]: http://erratique.ch/software/fmt 41 | [logs]: http://erratique.ch/software/logs 42 | [bos]: http://erratique.ch/software/bos 43 | [cmdliner]: http://erratique.ch/software/cmdliner 44 | [webbrowser]: http://erratique.ch/software/webbrowser 45 | """ 46 | url { 47 | src: "http://erratique.ch/software/topkg/releases/topkg-1.0.0.tbz" 48 | checksum: "md5=e3d76bda06bf68cb5853caf6627da603" 49 | } 50 | -------------------------------------------------------------------------------- /esy.lock/opam/tyxml.4.3.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "dev@ocsigen.org" 3 | homepage: "https://github.com/ocsigen/tyxml/" 4 | bug-reports: "https://github.com/ocsigen/tyxml/issues" 5 | doc: "https://ocsigen.org/tyxml/manual/" 6 | dev-repo: "git+https://github.com/ocsigen/tyxml.git" 7 | license: "LGPL-2.1 with OCaml linking exception" 8 | 9 | build: [ 10 | ["dune" "subst"] {pinned} 11 | ["dune" "build" "-p" name "-j" jobs] 12 | ["dune" "runtest" "-p" name "-j" jobs] {with-test} 13 | ] 14 | 15 | depends: [ 16 | "ocaml" {>= "4.02"} 17 | "dune" {build} 18 | "alcotest" {with-test} 19 | "seq" 20 | "uutf" {>= "1.0.0"} 21 | "re" {>= "1.5.0"} 22 | ] 23 | 24 | synopsis:"TyXML is a library for building correct HTML and SVG documents" 25 | description:""" 26 | TyXML provides a set of convenient combinators that uses the OCaml 27 | type system to ensure the validity of the generated documents. TyXML 28 | can be used with any representation of HTML and SVG: the textual one, 29 | provided directly by this package, or DOM trees (`js_of_ocaml-tyxml`) 30 | virtual DOM (`virtual-dom`) and reactive or replicated trees 31 | (`eliom`). You can also create your own representation and use it to 32 | instantiate a new set of combinators. 33 | 34 | ```ocaml 35 | open Tyxml 36 | let to_ocaml = Html.(a ~a:[a_href "ocaml.org"] [txt "OCaml!"]) 37 | ``` 38 | """ 39 | authors: "The ocsigen team" 40 | url { 41 | src: 42 | "https://github.com/ocsigen/tyxml/releases/download/4.3.0/tyxml-4.3.0.tbz" 43 | checksum: "md5=fd834a567f813bf447cab5f4c3a723e2" 44 | } 45 | -------------------------------------------------------------------------------- /esy.lock/opam/uchar.0.0.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://ocaml.org" 5 | doc: "https://ocaml.github.io/uchar/" 6 | dev-repo: "git+https://github.com/ocaml/uchar.git" 7 | bug-reports: "https://github.com/ocaml/uchar/issues" 8 | tags: [ "text" "character" "unicode" "compatibility" "org:ocaml.org" ] 9 | license: "typeof OCaml system" 10 | depends: [ 11 | "ocaml" {>= "3.12.0"} 12 | "ocamlbuild" {build} 13 | ] 14 | build: [ 15 | ["ocaml" "pkg/git.ml"] 16 | [ 17 | "ocaml" 18 | "pkg/build.ml" 19 | "native=%{ocaml:native}%" 20 | "native-dynlink=%{ocaml:native-dynlink}%" 21 | ] 22 | ] 23 | synopsis: "Compatibility library for OCaml's Uchar module" 24 | description: """ 25 | The `uchar` package provides a compatibility library for the 26 | [`Uchar`][1] module introduced in OCaml 4.03. 27 | 28 | The `uchar` package is distributed under the license of the OCaml 29 | compiler. See [LICENSE](LICENSE) for details. 30 | 31 | [1]: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Uchar.html""" 32 | url { 33 | src: 34 | "https://github.com/ocaml/uchar/releases/download/v0.0.2/uchar-0.0.2.tbz" 35 | checksum: "md5=c9ba2c738d264c420c642f7bb1cf4a36" 36 | } 37 | -------------------------------------------------------------------------------- /esy.lock/opam/uuidm.0.9.7/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "https://erratique.ch/software/uuidm" 5 | doc: "https://erratique.ch/software/uuidm/doc/Uuidm" 6 | dev-repo: "git+https://erratique.ch/repos/uuidm.git" 7 | bug-reports: "https://github.com/dbuenzli/uuidm/issues" 8 | tags: [ "uuid" "codec" "org:erratique" ] 9 | license: "ISC" 10 | depends: [ 11 | "ocaml" {>= "4.03.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {build} 14 | "topkg" {build} ] 15 | depopts: [ "cmdliner" ] 16 | build: 17 | [ "ocaml" "pkg/pkg.ml" "build" 18 | "--pinned" "%{pinned}%" 19 | "--with-cmdliner" "%{cmdliner:installed}%" ] 20 | synopsis: """Universally unique identifiers (UUIDs) for OCaml""" 21 | description: """\ 22 | 23 | Uuidm is an OCaml module implementing 128 bits universally unique 24 | identifiers version 3, 5 (named based with MD5, SHA-1 hashing) and 4 25 | (random based) according to [RFC 4122][rfc4122]. 26 | 27 | Uuidm has no dependency and is distributed under the ISC license. 28 | 29 | [rfc4122]: http://tools.ietf.org/html/rfc4122 30 | """ 31 | url { 32 | archive: "https://erratique.ch/software/uuidm/releases/uuidm-0.9.7.tbz" 33 | checksum: "54658248e3981d8c05237d0a4277ccd3" 34 | } 35 | -------------------------------------------------------------------------------- /esy.lock/opam/uutf.1.0.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/uutf" 5 | doc: "http://erratique.ch/software/uutf/doc/Uutf" 6 | dev-repo: "git+http://erratique.ch/repos/uutf.git" 7 | bug-reports: "https://github.com/dbuenzli/uutf/issues" 8 | tags: [ "unicode" "text" "utf-8" "utf-16" "codec" "org:erratique" ] 9 | license: "ISC" 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {build} 14 | "topkg" {build} 15 | "uchar" 16 | ] 17 | depopts: ["cmdliner"] 18 | conflicts: ["cmdliner" { < "0.9.6"} ] 19 | build: [[ 20 | "ocaml" "pkg/pkg.ml" "build" 21 | "--pinned" "%{pinned}%" 22 | "--with-cmdliner" "%{cmdliner:installed}%" ]] 23 | synopsis: """Non-blocking streaming Unicode codec for OCaml""" 24 | description: """\ 25 | 26 | Uutf is a non-blocking streaming codec to decode and encode the UTF-8, 27 | UTF-16, UTF-16LE and UTF-16BE encoding schemes. It can efficiently 28 | work character by character without blocking on IO. Decoders perform 29 | character position tracking and support newline normalization. 30 | 31 | Functions are also provided to fold over the characters of UTF encoded 32 | OCaml string values and to directly encode characters in OCaml 33 | Buffer.t values. 34 | 35 | Uutf has no dependency and is distributed under the ISC license. 36 | """ 37 | url { 38 | archive: "http://erratique.ch/software/uutf/releases/uutf-1.0.2.tbz" 39 | checksum: "a7c542405a39630c689a82bd7ef2292c" 40 | } 41 | -------------------------------------------------------------------------------- /esy.lock/opam/yojson.1.7.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | homepage: "https://github.com/ocaml-community/yojson" 5 | bug-reports: "https://github.com/ocaml-community/yojson/issues" 6 | dev-repo: "git+https://github.com/ocaml-community/yojson.git" 7 | doc: "https://ocaml-community.github.io/yojson/" 8 | build: [ 9 | ["dune" "subst"] {pinned} 10 | ["dune" "build" "-p" name "-j" jobs] 11 | ] 12 | run-test: [["dune" "runtest" "-p" name "-j" jobs]] 13 | depends: [ 14 | "ocaml" {>= "4.02.3"} 15 | "dune" {build} 16 | "cppo" {build} 17 | "easy-format" 18 | "biniou" {>= "1.2.0"} 19 | "alcotest" {with-test & >= "0.8.5"} 20 | ] 21 | synopsis: 22 | "Yojson is an optimized parsing and printing library for the JSON format" 23 | description: """ 24 | Yojson is an optimized parsing and printing library for the JSON format. 25 | 26 | It addresses a few shortcomings of json-wheel including 2x speedup, 27 | polymorphic variants and optional syntax for tuples and variants. 28 | 29 | ydump is a pretty-printing command-line program provided with the 30 | yojson package. 31 | 32 | The program atdgen can be used to derive OCaml-JSON serializers and 33 | deserializers from type definitions.""" 34 | url { 35 | src: 36 | "https://github.com/ocaml-community/yojson/releases/download/1.7.0/yojson-1.7.0.tbz" 37 | checksum: "md5=b89d39ca3f8c532abe5f547ad3b8f84d" 38 | } 39 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__dune_opam__c__1.8.2_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "ocaml", 5 | "bootstrap.ml" 6 | ], 7 | [ 8 | "./boot.exe", 9 | "--release", 10 | "-j", 11 | "4" 12 | ] 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__merlin_extend_opam__c__0.3_opam_override/files/merlin-extend-winfix.patch: -------------------------------------------------------------------------------- 1 | --- ./extend_helper.ml 2 | +++ ./extend_helper.ml 3 | @@ -1,13 +1,6 @@ 4 | -(*pp cppo -V OCAML:`ocamlc -version` *) 5 | open Parsetree 6 | open Extend_protocol 7 | 8 | -#if OCAML_VERSION < (4, 3, 0) 9 | -# define CONST_STRING Asttypes.Const_string 10 | -#else 11 | -# define CONST_STRING Parsetree.Pconst_string 12 | -#endif 13 | - 14 | (** Default implementation for [Reader_def.print_outcome] using 15 | [Oprint] from compiler-libs *) 16 | let print_outcome_using_oprint ppf = function 17 | @@ -28,7 +21,7 @@ 18 | pstr_loc = Location.none; 19 | pstr_desc = Pstr_eval ({ 20 | pexp_loc = Location.none; 21 | - pexp_desc = Pexp_constant (CONST_STRING (msg, None)); 22 | + pexp_desc = Pexp_constant (Parsetree.Pconst_string (msg, None)); 23 | pexp_attributes = []; 24 | }, []); 25 | }] 26 | @@ -112,7 +105,7 @@ 27 | let msg = match payload with 28 | | PStr [{ 29 | pstr_desc = Pstr_eval ({ 30 | - pexp_desc = Pexp_constant (CONST_STRING (msg, _)); 31 | + pexp_desc = Pexp_constant (Parsetree.Pconst_string (msg, _)); 32 | }, _); 33 | }] -> msg 34 | | _ -> "Warning: extension produced an incorrect syntax-error node" 35 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__merlin_extend_opam__c__0.3_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "bash", 5 | "-c", 6 | "#{os == 'windows' ? 'patch -p1 < merlin-extend-winfix.patch' : 'true'}" 7 | ], 8 | [ 9 | "make" 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__ocamlbuild_opam__c__0.14.0_opam_override/files/ocamlbuild-0.14.0.patch: -------------------------------------------------------------------------------- 1 | --- ./Makefile 2 | +++ ./Makefile 3 | @@ -213,7 +213,7 @@ 4 | rm -f man/ocamlbuild.1 5 | 6 | man/options_man.byte: src/ocamlbuild_pack.cmo 7 | - $(OCAMLC) $^ -I src man/options_man.ml -o man/options_man.byte 8 | + $(OCAMLC) -I +unix unix.cma $^ -I src man/options_man.ml -o man/options_man.byte 9 | 10 | clean:: 11 | rm -f man/options_man.cm* 12 | --- ./src/command.ml 13 | +++ ./src/command.ml 14 | @@ -148,9 +148,10 @@ 15 | let self = string_of_command_spec_with_calls call_with_tags call_with_target resolve_virtuals in 16 | let b = Buffer.create 256 in 17 | (* The best way to prevent bash from switching to its windows-style 18 | - * quote-handling is to prepend an empty string before the command name. *) 19 | + * quote-handling is to prepend an empty string before the command name. 20 | + * space seems to work, too - and the ouput is nicer *) 21 | if Sys.os_type = "Win32" then 22 | - Buffer.add_string b "''"; 23 | + Buffer.add_char b ' '; 24 | let first = ref true in 25 | let put_space () = 26 | if !first then 27 | @@ -260,7 +261,7 @@ 28 | 29 | let execute_many ?(quiet=false) ?(pretend=false) cmds = 30 | add_parallel_stat (List.length cmds); 31 | - let degraded = !*My_unix.is_degraded || Sys.os_type = "Win32" in 32 | + let degraded = !*My_unix.is_degraded in 33 | let jobs = !jobs in 34 | if jobs < 0 then invalid_arg "jobs < 0"; 35 | let max_jobs = if jobs = 0 then None else Some jobs in 36 | --- ./src/findlib.ml 37 | +++ ./src/findlib.ml 38 | @@ -66,9 +66,6 @@ 39 | (fun command -> lexer & Lexing.from_string & run_and_read command) 40 | command 41 | 42 | -let run_and_read command = 43 | - Printf.ksprintf run_and_read command 44 | - 45 | let rec query name = 46 | try 47 | Hashtbl.find packages name 48 | @@ -135,7 +132,8 @@ 49 | with Not_found -> s 50 | 51 | let list () = 52 | - List.map before_space (split_nl & run_and_read "%s list" ocamlfind) 53 | + let cmd = Shell.quote_filename_if_needed ocamlfind ^ " list" in 54 | + List.map before_space (split_nl & run_and_read cmd) 55 | 56 | (* The closure algorithm is easy because the dependencies are already closed 57 | and sorted for each package. We only have to make the union. We could also 58 | --- ./src/main.ml 59 | +++ ./src/main.ml 60 | @@ -162,6 +162,9 @@ 61 | Tags.mem "traverse" tags 62 | || List.exists (Pathname.is_prefix path_name) !Options.include_dirs 63 | || List.exists (Pathname.is_prefix path_name) target_dirs) 64 | + && ((* beware: !Options.build_dir is an absolute directory *) 65 | + Pathname.normalize !Options.build_dir 66 | + <> Pathname.normalize (Pathname.pwd/path_name)) 67 | end 68 | end 69 | end 70 | --- ./src/my_std.ml 71 | +++ ./src/my_std.ml 72 | @@ -271,13 +271,107 @@ 73 | try Array.iter (fun x -> if x = basename then raise Exit) a; false 74 | with Exit -> true 75 | 76 | +let command_plain = function 77 | +| [| |] -> 0 78 | +| margv -> 79 | + let rec waitpid a b = 80 | + match Unix.waitpid a b with 81 | + | exception (Unix.Unix_error(Unix.EINTR,_,_)) -> waitpid a b 82 | + | x -> x 83 | + in 84 | + let pid = Unix.(create_process margv.(0) margv stdin stdout stderr) in 85 | + let pid', process_status = waitpid [] pid in 86 | + assert (pid = pid'); 87 | + match process_status with 88 | + | Unix.WEXITED n -> n 89 | + | Unix.WSIGNALED _ -> 2 (* like OCaml's uncaught exceptions *) 90 | + | Unix.WSTOPPED _ -> 127 91 | + 92 | +(* can't use Lexers because of circular dependency *) 93 | +let split_path_win str = 94 | + let rec aux pos = 95 | + try 96 | + let i = String.index_from str pos ';' in 97 | + let len = i - pos in 98 | + if len = 0 then 99 | + aux (succ i) 100 | + else 101 | + String.sub str pos (i - pos) :: aux (succ i) 102 | + with Not_found | Invalid_argument _ -> 103 | + let len = String.length str - pos in 104 | + if len = 0 then [] else [String.sub str pos len] 105 | + in 106 | + aux 0 107 | + 108 | +let windows_shell = lazy begin 109 | + let rec iter = function 110 | + | [] -> [| "bash.exe" ; "--norc" ; "--noprofile" |] 111 | + | hd::tl -> 112 | + let dash = Filename.concat hd "dash.exe" in 113 | + if Sys.file_exists dash then [|dash|] else 114 | + let bash = Filename.concat hd "bash.exe" in 115 | + if Sys.file_exists bash = false then iter tl else 116 | + (* if sh.exe and bash.exe exist in the same dir, choose sh.exe *) 117 | + let sh = Filename.concat hd "sh.exe" in 118 | + if Sys.file_exists sh then [|sh|] else [|bash ; "--norc" ; "--noprofile"|] 119 | + in 120 | + split_path_win (try Sys.getenv "PATH" with Not_found -> "") |> iter 121 | +end 122 | + 123 | +let prep_windows_cmd cmd = 124 | + (* workaround known ocaml bug, remove later *) 125 | + if String.contains cmd '\t' && String.contains cmd ' ' = false then 126 | + " " ^ cmd 127 | + else 128 | + cmd 129 | + 130 | +let run_with_shell = function 131 | +| "" -> 0 132 | +| cmd -> 133 | + let cmd = prep_windows_cmd cmd in 134 | + let shell = Lazy.force windows_shell in 135 | + let qlen = Filename.quote cmd |> String.length in 136 | + (* old versions of dash had problems with bs *) 137 | + try 138 | + if qlen < 7_900 then 139 | + command_plain (Array.append shell [| "-ec" ; cmd |]) 140 | + else begin 141 | + (* it can still work, if the called command is a cygwin tool *) 142 | + let ch_closed = ref false in 143 | + let file_deleted = ref false in 144 | + let fln,ch = 145 | + Filename.open_temp_file 146 | + ~mode:[Open_binary] 147 | + "ocamlbuildtmp" 148 | + ".sh" 149 | + in 150 | + try 151 | + let f_slash = String.map ( fun x -> if x = '\\' then '/' else x ) fln in 152 | + output_string ch cmd; 153 | + ch_closed:= true; 154 | + close_out ch; 155 | + let ret = command_plain (Array.append shell [| "-e" ; f_slash |]) in 156 | + file_deleted:= true; 157 | + Sys.remove fln; 158 | + ret 159 | + with 160 | + | x -> 161 | + if !ch_closed = false then 162 | + close_out_noerr ch; 163 | + if !file_deleted = false then 164 | + (try Sys.remove fln with _ -> ()); 165 | + raise x 166 | + end 167 | + with 168 | + | (Unix.Unix_error _) as x -> 169 | + (* Sys.command doesn't raise an exception, so run_with_shell also won't 170 | + raise *) 171 | + Printexc.to_string x ^ ":" ^ cmd |> prerr_endline; 172 | + 1 173 | + 174 | let sys_command = 175 | - match Sys.os_type with 176 | - | "Win32" -> fun cmd -> 177 | - if cmd = "" then 0 else 178 | - let cmd = "bash --norc -c " ^ Filename.quote cmd in 179 | - Sys.command cmd 180 | - | _ -> fun cmd -> if cmd = "" then 0 else Sys.command cmd 181 | + if Sys.win32 then run_with_shell 182 | + else fun cmd -> if cmd = "" then 0 else Sys.command cmd 183 | 184 | (* FIXME warning fix and use Filename.concat *) 185 | let filename_concat x y = 186 | --- ./src/my_std.mli 187 | +++ ./src/my_std.mli 188 | @@ -69,3 +69,6 @@ 189 | 190 | val split_ocaml_version : (int * int * int * string) option 191 | (** (major, minor, patchlevel, rest) *) 192 | + 193 | +val windows_shell : string array Lazy.t 194 | +val prep_windows_cmd : string -> string 195 | --- ./src/ocamlbuild_executor.ml 196 | +++ ./src/ocamlbuild_executor.ml 197 | @@ -34,6 +34,8 @@ 198 | job_stdin : out_channel; 199 | job_stderr : in_channel; 200 | job_buffer : Buffer.t; 201 | + job_pid : int; 202 | + job_tmp_file: string option; 203 | mutable job_dying : bool; 204 | };; 205 | 206 | @@ -76,6 +78,61 @@ 207 | in 208 | loop 0 209 | ;; 210 | + 211 | +let open_process_full_win cmd env = 212 | + let (in_read, in_write) = Unix.pipe () in 213 | + let (out_read, out_write) = Unix.pipe () in 214 | + let (err_read, err_write) = Unix.pipe () in 215 | + Unix.set_close_on_exec in_read; 216 | + Unix.set_close_on_exec out_write; 217 | + Unix.set_close_on_exec err_read; 218 | + let inchan = Unix.in_channel_of_descr in_read in 219 | + let outchan = Unix.out_channel_of_descr out_write in 220 | + let errchan = Unix.in_channel_of_descr err_read in 221 | + let shell = Lazy.force Ocamlbuild_pack.My_std.windows_shell in 222 | + let test_cmd = 223 | + String.concat " " (List.map Filename.quote (Array.to_list shell)) ^ 224 | + "-ec " ^ 225 | + Filename.quote (Ocamlbuild_pack.My_std.prep_windows_cmd cmd) in 226 | + let argv,tmp_file = 227 | + if String.length test_cmd < 7_900 then 228 | + Array.append 229 | + shell 230 | + [| "-ec" ; Ocamlbuild_pack.My_std.prep_windows_cmd cmd |],None 231 | + else 232 | + let fln,ch = Filename.open_temp_file ~mode:[Open_binary] "ocamlbuild" ".sh" in 233 | + output_string ch (Ocamlbuild_pack.My_std.prep_windows_cmd cmd); 234 | + close_out ch; 235 | + let fln' = String.map (function '\\' -> '/' | c -> c) fln in 236 | + Array.append 237 | + shell 238 | + [| "-c" ; fln' |], Some fln in 239 | + let pid = 240 | + Unix.create_process_env argv.(0) argv env out_read in_write err_write in 241 | + Unix.close out_read; 242 | + Unix.close in_write; 243 | + Unix.close err_write; 244 | + (pid, inchan, outchan, errchan,tmp_file) 245 | + 246 | +let close_process_full_win (pid,inchan, outchan, errchan, tmp_file) = 247 | + let delete tmp_file = 248 | + match tmp_file with 249 | + | None -> () 250 | + | Some x -> try Sys.remove x with Sys_error _ -> () in 251 | + let tmp_file_deleted = ref false in 252 | + try 253 | + close_in inchan; 254 | + close_out outchan; 255 | + close_in errchan; 256 | + let res = snd(Unix.waitpid [] pid) in 257 | + tmp_file_deleted := true; 258 | + delete tmp_file; 259 | + res 260 | + with 261 | + | x when tmp_file <> None && !tmp_file_deleted = false -> 262 | + delete tmp_file; 263 | + raise x 264 | + 265 | (* ***) 266 | (*** execute *) 267 | (* XXX: Add test for non reentrancy *) 268 | @@ -130,10 +187,16 @@ 269 | (*** add_job *) 270 | let add_job cmd rest result id = 271 | (*display begin fun oc -> fp oc "Job %a is %s\n%!" print_job_id id cmd; end;*) 272 | - let (stdout', stdin', stderr') = open_process_full cmd env in 273 | + let (pid,stdout', stdin', stderr', tmp_file) = 274 | + if Sys.win32 then open_process_full_win cmd env else 275 | + let a,b,c = open_process_full cmd env in 276 | + -1,a,b,c,None 277 | + in 278 | incr jobs_active; 279 | - set_nonblock (doi stdout'); 280 | - set_nonblock (doi stderr'); 281 | + if not Sys.win32 then ( 282 | + set_nonblock (doi stdout'); 283 | + set_nonblock (doi stderr'); 284 | + ); 285 | let job = 286 | { job_id = id; 287 | job_command = cmd; 288 | @@ -143,7 +206,9 @@ 289 | job_stdin = stdin'; 290 | job_stderr = stderr'; 291 | job_buffer = Buffer.create 1024; 292 | - job_dying = false } 293 | + job_dying = false; 294 | + job_tmp_file = tmp_file; 295 | + job_pid = pid } 296 | in 297 | outputs := FDM.add (doi stdout') job (FDM.add (doi stderr') job !outputs); 298 | jobs := JS.add job !jobs; 299 | @@ -199,6 +264,7 @@ 300 | try 301 | read fd u 0 (Bytes.length u) 302 | with 303 | + | Unix.Unix_error(Unix.EPIPE,_,_) when Sys.win32 -> 0 304 | | Unix.Unix_error(e,_,_) -> 305 | let msg = error_message e in 306 | display (fun oc -> fp oc 307 | @@ -241,14 +307,19 @@ 308 | decr jobs_active; 309 | 310 | (* PR#5371: we would get EAGAIN below otherwise *) 311 | - clear_nonblock (doi job.job_stdout); 312 | - clear_nonblock (doi job.job_stderr); 313 | - 314 | + if not Sys.win32 then ( 315 | + clear_nonblock (doi job.job_stdout); 316 | + clear_nonblock (doi job.job_stderr); 317 | + ); 318 | do_read ~loop:true (doi job.job_stdout) job; 319 | do_read ~loop:true (doi job.job_stderr) job; 320 | outputs := FDM.remove (doi job.job_stdout) (FDM.remove (doi job.job_stderr) !outputs); 321 | jobs := JS.remove job !jobs; 322 | - let status = close_process_full (job.job_stdout, job.job_stdin, job.job_stderr) in 323 | + let status = 324 | + if Sys.win32 then 325 | + close_process_full_win (job.job_pid, job.job_stdout, job.job_stdin, job.job_stderr, job.job_tmp_file) 326 | + else 327 | + close_process_full (job.job_stdout, job.job_stdin, job.job_stderr) in 328 | 329 | let shown = ref false in 330 | 331 | --- ./src/ocamlbuild_unix_plugin.ml 332 | +++ ./src/ocamlbuild_unix_plugin.ml 333 | @@ -48,12 +48,22 @@ 334 | end 335 | 336 | let run_and_open s kont = 337 | + let s_orig = s in 338 | + let s = 339 | + (* Be consistent! My_unix.run_and_open uses My_std.sys_command and 340 | + sys_command uses bash. *) 341 | + if Sys.win32 = false then s else 342 | + let l = match Lazy.force My_std.windows_shell |> Array.to_list with 343 | + | hd::tl -> (Filename.quote hd)::tl 344 | + | _ -> assert false in 345 | + "\"" ^ (String.concat " " l) ^ " -ec " ^ Filename.quote (" " ^ s) ^ "\"" 346 | + in 347 | let ic = Unix.open_process_in s in 348 | let close () = 349 | match Unix.close_process_in ic with 350 | | Unix.WEXITED 0 -> () 351 | | Unix.WEXITED _ | Unix.WSIGNALED _ | Unix.WSTOPPED _ -> 352 | - failwith (Printf.sprintf "Error while running: %s" s) in 353 | + failwith (Printf.sprintf "Error while running: %s" s_orig) in 354 | let res = try 355 | kont ic 356 | with e -> (close (); raise e) 357 | --- ./src/options.ml 358 | +++ ./src/options.ml 359 | @@ -174,11 +174,24 @@ 360 | build_dir := Filename.concat (Sys.getcwd ()) s 361 | else 362 | build_dir := s 363 | + 364 | +let slashify = 365 | + if Sys.win32 then fun p -> String.map (function '\\' -> '/' | x -> x) p 366 | + else fun p ->p 367 | + 368 | +let sb () = 369 | + match Sys.os_type with 370 | + | "Win32" -> 371 | + (try set_binary_mode_out stdout true with _ -> ()); 372 | + | _ -> () 373 | + 374 | + 375 | let spec = ref ( 376 | let print_version () = 377 | + sb (); 378 | Printf.printf "ocamlbuild %s\n%!" Ocamlbuild_config.version; raise Exit_OK 379 | in 380 | - let print_vnum () = print_endline Ocamlbuild_config.version; raise Exit_OK in 381 | + let print_vnum () = sb (); print_endline Ocamlbuild_config.version; raise Exit_OK in 382 | Arg.align 383 | [ 384 | "-version", Unit print_version , " Display the version"; 385 | @@ -257,8 +270,8 @@ 386 | "-build-dir", String set_build_dir, " Set build directory (implies no-links)"; 387 | "-install-lib-dir", Set_string Ocamlbuild_where.libdir, " Set the install library directory"; 388 | "-install-bin-dir", Set_string Ocamlbuild_where.bindir, " Set the install binary directory"; 389 | - "-where", Unit (fun () -> print_endline !Ocamlbuild_where.libdir; raise Exit_OK), " Display the install library directory"; 390 | - "-which", String (fun cmd -> print_endline (find_tool cmd); raise Exit_OK), " Display path to the tool command"; 391 | + "-where", Unit (fun () -> sb (); print_endline (slashify !Ocamlbuild_where.libdir); raise Exit_OK), " Display the install library directory"; 392 | + "-which", String (fun cmd -> sb (); print_endline (slashify (find_tool cmd)); raise Exit_OK), " Display path to the tool command"; 393 | "-ocamlc", set_cmd ocamlc, " Set the OCaml bytecode compiler"; 394 | "-plugin-ocamlc", set_cmd plugin_ocamlc, " Set the OCaml bytecode compiler \ 395 | used when building myocamlbuild.ml (only)"; 396 | --- ./src/pathname.ml 397 | +++ ./src/pathname.ml 398 | @@ -84,6 +84,26 @@ 399 | | x :: xs -> x :: normalize_list xs 400 | 401 | let normalize x = 402 | + let x = 403 | + if Sys.win32 = false then 404 | + x 405 | + else 406 | + let len = String.length x in 407 | + let b = Bytes.create len in 408 | + for i = 0 to pred len do 409 | + match x.[i] with 410 | + | '\\' -> Bytes.set b i '/' 411 | + | c -> Bytes.set b i c 412 | + done; 413 | + if len > 1 then ( 414 | + let c1 = Bytes.get b 0 in 415 | + let c2 = Bytes.get b 1 in 416 | + if c2 = ':' && c1 >= 'a' && c1 <= 'z' && 417 | + ( len = 2 || Bytes.get b 2 = '/') then 418 | + Bytes.set b 0 (Char.uppercase_ascii c1) 419 | + ); 420 | + Bytes.unsafe_to_string b 421 | + in 422 | if Glob.eval not_normal_form_re x then 423 | let root, paths = split x in 424 | join root (normalize_list paths) 425 | --- ./src/shell.ml 426 | +++ ./src/shell.ml 427 | @@ -24,12 +24,26 @@ 428 | | 'a'..'z' | 'A'..'Z' | '0'..'9' | '.' | '-' | '/' | '_' | ':' | '@' | '+' | ',' -> loop (pos + 1) 429 | | _ -> false in 430 | loop 0 431 | + 432 | +let generic_quote quotequote s = 433 | + let l = String.length s in 434 | + let b = Buffer.create (l + 20) in 435 | + Buffer.add_char b '\''; 436 | + for i = 0 to l - 1 do 437 | + if s.[i] = '\'' 438 | + then Buffer.add_string b quotequote 439 | + else Buffer.add_char b s.[i] 440 | + done; 441 | + Buffer.add_char b '\''; 442 | + Buffer.contents b 443 | +let unix_quote = generic_quote "'\\''" 444 | + 445 | let quote_filename_if_needed s = 446 | if is_simple_filename s then s 447 | (* We should probably be using [Filename.unix_quote] except that function 448 | * isn't exported. Users on Windows will have to live with not being able to 449 | * install OCaml into c:\o'caml. Too bad. *) 450 | - else if Sys.os_type = "Win32" then Printf.sprintf "'%s'" s 451 | + else if Sys.os_type = "Win32" then unix_quote s 452 | else Filename.quote s 453 | let chdir dir = 454 | reset_filesys_cache (); 455 | @@ -37,7 +51,7 @@ 456 | let run args target = 457 | reset_readdir_cache (); 458 | let cmd = String.concat " " (List.map quote_filename_if_needed args) in 459 | - if !*My_unix.is_degraded || Sys.os_type = "Win32" then 460 | + if !*My_unix.is_degraded then 461 | begin 462 | Log.event cmd target Tags.empty; 463 | let st = sys_command cmd in 464 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__ocamlbuild_opam__c__0.14.0_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "bash", 5 | "-c", 6 | "#{os == 'windows' ? 'patch -p1 < ocamlbuild-0.14.0.patch' : 'true'}" 7 | ], 8 | [ 9 | "make", 10 | "-f", 11 | "configure.make", 12 | "all", 13 | "OCAMLBUILD_PREFIX=#{self.install}", 14 | "OCAMLBUILD_BINDIR=#{self.bin}", 15 | "OCAMLBUILD_LIBDIR=#{self.lib}", 16 | "OCAMLBUILD_MANDIR=#{self.man}", 17 | "OCAMLBUILD_NATIVE=true", 18 | "OCAMLBUILD_NATIVE_TOOLS=true" 19 | ], 20 | [ 21 | "make", 22 | "check-if-preinstalled", 23 | "all", 24 | "#{os == 'windows' ? 'install' : 'opam-install'}" 25 | ] 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /esy.lock/overrides/opam__s__ocamlfind_opam__c__1.8.0_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "bash", 5 | "-c", 6 | "#{os == 'windows' ? 'patch -p1 < findlib-1.8.0.patch' : 'true'}" 7 | ], 8 | [ 9 | "./configure", 10 | "-bindir", 11 | "#{self.bin}", 12 | "-sitelib", 13 | "#{self.lib}", 14 | "-mandir", 15 | "#{self.man}", 16 | "-config", 17 | "#{self.lib}/findlib.conf", 18 | "-no-custom", 19 | "-no-topfind" 20 | ], 21 | [ 22 | "make", 23 | "all" 24 | ], 25 | [ 26 | "make", 27 | "opt" 28 | ] 29 | ], 30 | "install": [ 31 | [ 32 | "make", 33 | "install" 34 | ], 35 | [ 36 | "install", 37 | "-m", 38 | "0755", 39 | "ocaml-stub", 40 | "#{self.bin}/ocaml" 41 | ], 42 | [ 43 | "mkdir", 44 | "-p", 45 | "#{self.toplevel}" 46 | ], 47 | [ 48 | "install", 49 | "-m", 50 | "0644", 51 | "src/findlib/topfind", 52 | "#{self.toplevel}/topfind" 53 | ] 54 | ], 55 | "exportedEnv": { 56 | "OCAML_TOPLEVEL_PATH": { 57 | "val": "#{self.toplevel}", 58 | "scope": "global" 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/01_spawning_processes/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name main) 3 | (libraries reactor logs logs.fmt fmt fmt.tty)) 4 | -------------------------------------------------------------------------------- /examples/01_spawning_processes/main.re: -------------------------------------------------------------------------------- 1 | /** 2 | # Spawning Processes 3 | 4 | Hello! 5 | 6 | In this first lab we will learn how to spawn processes and what they can do. 7 | It's a pretty straightforward lab, as we will introduce only spawning, 8 | becoming, and exiting the Reactor system. 9 | 10 | Before, I'll do some hand-wavy log setup ✨ 11 | */ 12 | Fmt_tty.setup_std_outputs(); 13 | Logs.set_level(Some(Logs.Info)); 14 | Logs.set_reporter(Logs_fmt.reporter()); 15 | 16 | /** 17 | Ta-da! Okay, last thing to do is to actually set up the Reactor system. For 18 | now we just need to know that this setup needs to be in place _before_ our 19 | application starts. 20 | 21 | As a bonus we will open the [!Reactor.System] module to get access to a few 22 | handy functions. 23 | */ 24 | Reactor.Node.(Policy.default() |> setup); 25 | 26 | open Reactor.System; 27 | 28 | /** 29 | Great! We are ready to start now, so lets do that by defining what is 30 | spawning and becoming. 31 | 32 | *Spawning* is the act of creating a new Process. To spawn a process, we need 33 | a function that will define the behavior of the process, and an initial 34 | state. 35 | 36 | *Becoming* is what Processes do to change their state, and it behaves like a 37 | tail-recursive call. This means that state is not mutable, but rather that a 38 | process must compute it's next state, and it will essentially call itself 39 | with it. 40 | 41 | The example below will spawn a process that simply keeps state and never 42 | terminates. 43 | */ 44 | let _ = spawn((_ctx, state) => `Become(state), 0); 45 | 46 | /** 47 | Yes, it's a pretty useless process, but it shows how easy it is to spawn them 48 | just by using a lambda :) The type of the state in this case is inferred from 49 | the initial state (`0`). The return value is being ignored, and we will see 50 | how to use it later on. 51 | 52 | The way this works is that whatever a process decides to __become__, will be 53 | the next iterations state. 54 | 55 | Here's another example that changes its state on each iteration. If the state 56 | is `true`, it becomes `false`, and viceversa. 57 | */ 58 | let _ = 59 | spawn( 60 | (_ctx, state) => 61 | switch (state) { 62 | | true => `Become(false) 63 | | _ => `Become(true) 64 | }, 65 | true, 66 | ); 67 | 68 | /** 69 | Because the body of a process is just a function, you can do many things in 70 | it too, including side-effects! 71 | */ 72 | let _ = 73 | spawn( 74 | (_ctx, state) => 75 | /** uncomment this to see the logs! */ 76 | /** Logs.app(m => m("Current state: %s", state)); */ 77 | `Become(state), 78 | "hello", 79 | ); 80 | 81 | /** 82 | Now that we've seen a little about how to spawn processes and evolve them, 83 | lets try changing the process below to call `exit()` when the counter 84 | reaches zero. 85 | 86 | `exit` is a function that normally is available in Reason/OCaml native to 87 | exit the current program. In this case, its been shadowed so that it 88 | performs a reasonable cleanup before continuing. 89 | */ 90 | let _ = spawn((_ctx, counter) => `Become(counter - 1), 100); 91 | 92 | /** 93 | Lastly, after we have set up our application, we need to tell Reactor that it 94 | should start executing our processes. 95 | 96 | We do this with the call below, which will block until some process calls 97 | `exit`. 98 | */ 99 | Reactor.Node.run(); 100 | 101 | /** 102 | And that's it for today! You're now ready to create thousands of processes 103 | that will evolve as they carry out tasks and eventually finish. 104 | */; 105 | -------------------------------------------------------------------------------- /examples/02_basic_message_passing/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name main) 3 | (libraries reactor logs logs.fmt fmt fmt.tty)) 4 | -------------------------------------------------------------------------------- /examples/02_basic_message_passing/main.re: -------------------------------------------------------------------------------- 1 | /** 2 | # Basic Message Passing 3 | 4 | In this lab we will learn how to send messages to a process, and how that 5 | process can consume those messages. 6 | 7 | Before, I'll do some hand-wavy log setup ✨ 8 | */ 9 | Fmt_tty.setup_std_outputs(); 10 | Logs.set_level(Some(Logs.Info)); 11 | Logs.set_reporter(Logs_fmt.reporter()); 12 | 13 | /** 14 | Ta-da! Okay, last thing to do is to actually set up the Reactor system. For 15 | now we just need to know that this setup needs to be in place _before_ our 16 | application starts. 17 | 18 | As a bonus we will open the [!Reactor.System] module to get access to a few 19 | handy functions. 20 | */ 21 | Reactor.Node.(Policy.default() |> setup); 22 | 23 | open Reactor.System; 24 | 25 | /** 26 | Great! We are ready to start now. 27 | 28 | Messages in Reactor are, deep inside, just strings. This seems like an 29 | overlook, but ultimately its a decision taken to allow for maximum 30 | flexibility while maintining the implementation of the library relatively 31 | simple. 32 | 33 | This means that it is completely up to you to use vanilla strings such as 34 | "hello" as messages, or if you want to pass around JSON, MsgPack, Protobuf, or 35 | OCaml Marshal bytes. 36 | 37 | For now we will assume that our messages are plain old strings, but we will 38 | look into custom encoders later on. 39 | 40 | Let's begin with a familiar process, but this time we will save it's _pid_. 41 | */ 42 | let pid = spawn((_ctx, state) => `Become(state), 0); 43 | 44 | /** 45 | Cool. This pid is needed to send messages to this process, and to send 46 | messages we can use the `send` function, or the `<-` operator. 47 | 48 | When we send a message, we are actually putting a copy of the message at the 49 | top of the mailbox for a particular process. This means that the process will 50 | have to consume all the earlier messages before it reads ours. 51 | 52 | Let's send two messages, "hello", and "world": 53 | */ 54 | send(pid, "hello"); 55 | pid <- "world"; 56 | 57 | /** 58 | That was easy. Unfortunately not much has happened, because our process isn't 59 | really checking for messages. 60 | 61 | Every process, as you may have seen, takes a `ctx` variable. We have ignored 62 | it up until now, but it's time to access one of the functions it exposes: 63 | `ctx.recv()`. 64 | 65 | The `recv` function will return an optional message. This value will be 66 | `None` if there are no new messages available for our process to consume, or 67 | `Some(msg)`, where `msg` will be the next message in the queue. 68 | 69 | It is worth noting that calling `recv` will effectively _consume_ a message 70 | out of the mailbox. 71 | 72 | Lets create a new process that will log every message it receives, and send it 73 | the same 2 messages: 74 | */ 75 | let pid' = 76 | spawn( 77 | (ctx, state) => { 78 | switch (ctx.recv()) { 79 | | Some(msg) => Logs.app(m => m("Received: %s", msg)) 80 | | None => () 81 | }; 82 | `Become(state); 83 | }, 84 | 0, 85 | ); 86 | pid' <- "hello"; 87 | pid' <- "world"; 88 | 89 | /** 90 | Magnificent. This new process actually checks for messages and prints them 91 | out. 92 | 93 | Thanks to the ability to pattern match, we can handle messages quite 94 | declaratively. For example, this next process will react only to the 95 | `"terminate"` message and terminate the system: 96 | */ 97 | let pid'' = 98 | spawn( 99 | (ctx, state) => 100 | switch (ctx.recv()) { 101 | | Some("pls exit") => 102 | /** replace this with a call to `exit()` */ `Terminate 103 | | _ => `Become(state) 104 | }, 105 | 0, 106 | ); 107 | pid'' <- "what"; 108 | pid'' <- "pls exit"; 109 | 110 | /** 111 | Lastly, after we have set up our application, we need to tell Reactor that it 112 | should start executing our processes. 113 | 114 | We do this with the call below, which will block until some process calls 115 | `exit`. 116 | */ 117 | Reactor.Node.run(); 118 | 119 | /** 120 | And that's it for today! You're now ready to create thousands of processes 121 | that will send messages to each other. 122 | */; 123 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # 🚀 reactor examples 👨‍🏫 2 | 3 | This section includes a series of small examples built in the form of _labs_ 4 | that you can read and work through to learn about reactor and how to use it. 5 | 6 | List of labs: 7 | 8 | 1. [Spawning Processes](./01_spawning_processes/main.re) 9 | 2. [Basic Message Passing](./02_basic_message_passing/main.re) 10 | 11 | ## Running Examples 12 | 13 | You can build all the examples by running: 14 | 15 | ```sh 16 | reactor/examples λ esy dune build @all 17 | ``` 18 | 19 | And you can run individual examples by running: 20 | 21 | ```sh 22 | reactor/examples λ esy dune exec ./01_spawning_processes/main.exe 23 | ``` 24 | 25 | All examples include a `main.re` file. 26 | -------------------------------------------------------------------------------- /examples/dummy.re: -------------------------------------------------------------------------------- 1 | open Reactor.System; 2 | 3 | /** Logging setup */ 4 | Fmt_tty.setup_std_outputs(); 5 | Logs.set_level(Some(Logs.Info)); 6 | Logs.set_reporter(Logs_fmt.reporter()); 7 | 8 | Reactor.Node.(Policy.default() |> setup); 9 | spawn((_, _) => exit(), ()); 10 | Reactor.Node.run(); 11 | 12 | /** Crashes are more frequent when running the node more than once */ 13 | Reactor.Node.(Policy.default() |> setup); 14 | spawn((_, _) => exit(), ()); 15 | Reactor.Node.run(); 16 | -------------------------------------------------------------------------------- /examples/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name dummy) 3 | (libraries reactor logs logs.fmt fmt fmt.tty)) 4 | -------------------------------------------------------------------------------- /examples/dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 1.6) 2 | (name reactor-examples) 3 | (using fmt 1.0) 4 | -------------------------------------------------------------------------------- /examples/esy.lock/.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | # Set eol to LF so files aren't converted to CRLF-eol on Windows. 3 | * text eol=lf 4 | -------------------------------------------------------------------------------- /examples/esy.lock/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Reset any possible .gitignore, we want all esy.lock to be un-ignored. 3 | !* 4 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/astring.0.8.3/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/astring" 5 | doc: "http://erratique.ch/software/astring/doc" 6 | dev-repo: "git+http://erratique.ch/repos/astring.git" 7 | bug-reports: "https://github.com/dbuenzli/astring/issues" 8 | tags: [ "string" "org:erratique" ] 9 | license: "ISC" 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {build} 14 | "topkg" {build} 15 | "base-bytes" 16 | ] 17 | build: [[ 18 | "ocaml" "pkg/pkg.ml" "build" 19 | "--pinned" "%{pinned}%" ]] 20 | synopsis: "Alternative String module for OCaml" 21 | description: """ 22 | Astring exposes an alternative `String` module for OCaml. This module 23 | tries to balance minimality and expressiveness for basic, index-free, 24 | string processing and provides types and functions for substrings, 25 | string sets and string maps. 26 | 27 | Remaining compatible with the OCaml `String` module is a non-goal. The 28 | `String` module exposed by Astring has exception safe functions, 29 | removes deprecated and rarely used functions, alters some signatures 30 | and names, adds a few missing functions and fully exploits OCaml's 31 | newfound string immutability. 32 | 33 | Astring depends only on the OCaml standard library. It is distributed 34 | under the ISC license.""" 35 | url { 36 | src: "http://erratique.ch/software/astring/releases/astring-0.8.3.tbz" 37 | checksum: "md5=c5bf6352b9ac27fbeab342740f4fa870" 38 | } 39 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/base-bytes.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: " " 3 | authors: " " 4 | homepage: " " 5 | depends: [ 6 | "ocaml" {>= "4.02.0"} 7 | "ocamlfind" {>= "1.5.3"} 8 | ] 9 | synopsis: "Bytes library distributed with the OCaml compiler" 10 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/base-threads.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "https://github.com/ocaml/opam-repository/issues" 3 | description: """ 4 | Threads library distributed with the OCaml compiler 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/base-unix.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "https://github.com/ocaml/opam-repository/issues" 3 | description: """ 4 | Unix library distributed with the OCaml compiler 5 | """ 6 | 7 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/biniou.1.2.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | 5 | homepage: "https://github.com/mjambon/biniou" 6 | bug-reports: "https://github.com/mjambon/biniou/issues" 7 | dev-repo: "git+https://github.com/mjambon/biniou.git" 8 | license: "BSD-3-Clause" 9 | 10 | build: [ 11 | ["jbuilder" "build" "-p" name "-j" jobs] 12 | ["jbuilder" "runtest" "-p" name] {with-test} 13 | ] 14 | depends: [ 15 | "ocaml" {>= "4.02.3"} 16 | "conf-which" {build} 17 | "jbuilder" {build & >= "1.0+beta7"} 18 | "easy-format" 19 | ] 20 | synopsis: 21 | "Binary data format designed for speed, safety, ease of use and backward compatibility as protocols evolve" 22 | url { 23 | src: "https://github.com/mjambon/biniou/archive/v1.2.0.tar.gz" 24 | checksum: "md5=f3e92358e832ed94eaf23ce622ccc2f9" 25 | } 26 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/conf-m4.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "tim@gfxmonk.net" 3 | homepage: "http://www.gnu.org/software/m4/m4.html" 4 | bug-reports: "https://github.com/ocaml/opam-repository/issues" 5 | authors: "GNU Project" 6 | license: "GPL-3" 7 | build: [["sh" "-exc" "echo | m4"]] 8 | depexts: [ 9 | ["m4"] {os-distribution = "debian"} 10 | ["m4"] {os-distribution = "ubuntu"} 11 | ["m4"] {os-distribution = "fedora"} 12 | ["m4"] {os-distribution = "rhel"} 13 | ["m4"] {os-distribution = "centos"} 14 | ["m4"] {os-distribution = "alpine"} 15 | ["m4"] {os-distribution = "nixos"} 16 | ["m4"] {os-family = "suse"} 17 | ["m4"] {os-distribution = "oraclelinux"} 18 | ["m4"] {os-distribution = "archlinux"} 19 | ] 20 | synopsis: "Virtual package relying on m4" 21 | description: 22 | "This package can only install if the m4 binary is installed on the system." 23 | flags: conf 24 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/conf-pkg-config.1.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "unixjunkie@sdf.org" 3 | authors: ["Francois Berenger"] 4 | homepage: "http://www.freedesktop.org/wiki/Software/pkg-config/" 5 | bug-reports: "https://github.com/ocaml/opam-repository/issues" 6 | license: "GPL" 7 | build: [ 8 | ["pkg-config" "--help"] 9 | ] 10 | install: [ 11 | ["ln" "-s" "/usr/local/bin/pkgconf" "%{bin}%/pkg-config"] {os = "openbsd"} 12 | ] 13 | remove: [ 14 | ["rm" "-f" "%{bin}%/pkg-config"] {os = "openbsd"} 15 | ] 16 | post-messages: [ 17 | "conf-pkg-config: A symlink to /usr/local/bin/pkgconf has been installed in the OPAM bin directory (%{bin}%) on your PATH as 'pkg-config'. This is necessary for correct operation." {os = "openbsd"} 18 | ] 19 | depexts: [ 20 | ["pkg-config"] {os-distribution = "debian"} 21 | ["pkg-config"] {os-distribution = "ubuntu"} 22 | ["pkg-config"] {os-distribution = "archlinux"} 23 | ["pkgconfig"] {os-distribution = "fedora"} 24 | ["pkgconfig"] {os-distribution = "centos"} 25 | ["pkgconfig"] {os-distribution = "mageia"} 26 | ["pkgconfig"] {os-distribution = "rhel"} 27 | ["pkgconfig"] {os-distribution = "oraclelinux"} 28 | ["pkgconfig"] {os-distribution = "alpine"} 29 | ["devel/pkgconf"] {os = "freebsd"} 30 | ["devel/pkgconf"] {os = "openbsd"} 31 | ["pkg-config"] {os = "macos" & os-distribution = "homebrew"} 32 | ["pkgconf"] {os = "freebsd"} 33 | ] 34 | synopsis: "Virtual package relying on pkg-config installation" 35 | description: """ 36 | This package can only install if the pkg-config package is installed 37 | on the system.""" 38 | flags: conf 39 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/conf-sdl2.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "blue-prawn" 3 | authors: ["Sam Lantinga"] 4 | homepage: "http://libsdl.org/" 5 | bug-reports: "https://github.com/ocaml/opam-repository/issues" 6 | license: "Zlib" 7 | build: [["pkg-config" "sdl2"]] 8 | depexts: [ 9 | ["sdl2-dev"] {os-distribution = "alpine"} 10 | ["sdl2"] {os-distribution = "archlinux"} 11 | ["libsdl2-dev"] {os-distribution = "debian"} 12 | ["SDL2-devel"] {os-distribution = "fedora"} 13 | ["sdl2"] {os = "freebsd"} 14 | ["sdl2"] {os = "macos" & os-distribution = "homebrew"} 15 | ["libsdl2-devel"] {os-distribution = "mageia"} 16 | ["sdl2"] {os = "openbsd"} 17 | ["sdl2"] {os-family = "suse"} 18 | ["libsdl2-dev"] {os-distribution = "ubuntu"} 19 | ] 20 | synopsis: "Virtual package relying on a SDL2 system installation" 21 | description: 22 | "This package can only install if libSDL2 is installed on the system." 23 | depends: ["conf-pkg-config" {build}] 24 | flags: conf 25 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/conf-which.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "unixjunkie@sdf.org" 3 | homepage: "http://www.gnu.org/software/which/" 4 | authors: "Carlo Wood" 5 | bug-reports: "https://github.com/ocaml/opam-repository/issues" 6 | license: "GPL-2+" 7 | build: [["which" "which"]] 8 | depexts: [ 9 | ["which"] {os-distribution = "centos"} 10 | ["which"] {os-distribution = "fedora"} 11 | ["which"] {os-family = "suse"} 12 | ["debianutils"] {os-distribution = "debian"} 13 | ["debianutils"] {os-distribution = "ubuntu"} 14 | ["which"] {os-distribution = "nixos"} 15 | ["which"] {os-distribution = "archlinux"} 16 | ] 17 | synopsis: "Virtual package relying on which" 18 | description: 19 | "This package can only install if the which program is installed on the system." 20 | flags: conf 21 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/cppo.1.6.5/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | homepage: "https://github.com/mjambon/cppo" 5 | dev-repo: "git+https://github.com/mjambon/cppo.git" 6 | bug-reports: "https://github.com/mjambon/cppo/issues" 7 | license: "BSD-3-Clause" 8 | 9 | build: [ 10 | ["jbuilder" "subst" "-p" name] {pinned} 11 | ["jbuilder" "build" "-p" name "-j" jobs] 12 | ["jbuilder" "runtest" "-p" name] {with-test} 13 | ] 14 | depends: [ 15 | "ocaml" 16 | "jbuilder" {build & >= "1.0+beta17"} 17 | "base-unix" 18 | ] 19 | synopsis: "Equivalent of the C preprocessor for OCaml programs" 20 | url { 21 | src: "https://github.com/mjambon/cppo/archive/v1.6.5.tar.gz" 22 | checksum: "md5=1cd25741d31417995b0973fe0b6f6c82" 23 | } 24 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ctypes-foreign.0.4.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | version: "0.4.0" 3 | maintainer: "yallop@gmail.com" 4 | homepage: "https://github.com/ocamllabs/ocaml-ctypes" 5 | dev-repo: "git+http://github.com/ocamllabs/ocaml-ctypes.git" 6 | bug-reports: "http://github.com/ocamllabs/ocaml-ctypes/issues" 7 | depexts: [ 8 | ["libffi-dev"] {os-distribution = "debian"} 9 | ["libffi-dev"] {os-distribution = "ubuntu"} 10 | ["libffi"] {os = "macos" & os-distribution = "homebrew"} 11 | ["libffi"] {os = "macos" & os-distribution = "macports"} 12 | ["libffi-devel"] {os-distribution = "centos"} 13 | ["libffi-devel"] {os-distribution = "oraclelinux"} 14 | ["libffi-devel"] {os-distribution = "fedora"} 15 | ["libffi-dev"] {os-distribution = "alpine"} 16 | ["libffi-devel"] {os-family = "suse"} 17 | ] 18 | tags: ["org:ocamllabs" "org:mirage"] 19 | post-messages: [ 20 | "This package requires libffi on your system" {failure} 21 | ] 22 | synopsis: "Virtual package for enabling the ctypes.foreign subpackage." 23 | description: """ 24 | `ctypes-foreign` is just a virtual OPAM package that determines 25 | whether the foreign subpackage should built as part of ctypes. 26 | In order to actually get the ctypes package, you should also: 27 | 28 | opam install ctypes ctypes-foreign 29 | 30 | You can verify the existence of the ocamlfind subpackage by: 31 | 32 | ocamlfind list | grep ctypes 33 | 34 | Which should output something like: 35 | 36 | ctypes (version: 0.4.1) 37 | ctypes.foreign (version: 0.4.1) 38 | ctypes.foreign.base (version: 0.4.1) 39 | ctypes.foreign.threaded (version: 0.4.1) 40 | ctypes.foreign.unthreaded (version: 0.4.1) 41 | ctypes.stubs (version: 0.4.1) 42 | ctypes.top (version: 0.4.1)""" 43 | authors: "yallop@gmail.com" 44 | depends: ["ocaml"] 45 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ctypes.0.14.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "yallop@gmail.com" 3 | homepage: "https://github.com/ocamllabs/ocaml-ctypes" 4 | doc: "http://ocamllabs.github.io/ocaml-ctypes" 5 | dev-repo: "git+http://github.com/ocamllabs/ocaml-ctypes.git" 6 | bug-reports: "http://github.com/ocamllabs/ocaml-ctypes/issues" 7 | license: "MIT" 8 | build: [ 9 | [make "XEN=%{mirage-xen:enable}%" "libffi.config"] 10 | {ctypes-foreign:installed} 11 | ["touch" "libffi.config"] {!ctypes-foreign:installed} 12 | [make "XEN=%{mirage-xen:enable}%" "ctypes-base" "ctypes-stubs"] 13 | [make "XEN=%{mirage-xen:enable}%" "ctypes-foreign"] 14 | {ctypes-foreign:installed} 15 | [make "test"] {with-test} 16 | ] 17 | install: [ 18 | [make "install" "XEN=%{mirage-xen:enable}%"] 19 | ] 20 | remove: [ 21 | ["ocamlfind" "remove" "ctypes"] 22 | ] 23 | depends: [ 24 | "ocaml" {>= "4.01.0"} 25 | "base-bytes" 26 | "integers" { < "0.3.0" } 27 | "ocamlfind" {build} 28 | "conf-pkg-config" {build} 29 | "lwt" {with-test & >= "2.4.7" & < "4.0.0"} 30 | "ounit" {with-test} 31 | "ctypes-foreign" {with-test} 32 | "conf-ncurses" {with-test} 33 | ] 34 | depopts: [ 35 | "ctypes-foreign" 36 | "mirage-xen" 37 | ] 38 | tags: ["org:ocamllabs" "org:mirage"] 39 | synopsis: "Combinators for binding to C libraries without writing any C." 40 | description: """ 41 | ctypes is a library for binding to C libraries using pure OCaml. The primary 42 | aim is to make writing C extensions as straightforward as possible. 43 | 44 | The core of ctypes is a set of combinators for describing the structure of C 45 | types -- numeric types, arrays, pointers, structs, unions and functions. You 46 | can use these combinators to describe the types of the functions that you want 47 | to call, then bind directly to those functions -- all without writing or 48 | generating any C! 49 | 50 | To install the optional `ctypes.foreign` interface (which uses `libffi` to 51 | provide dynamic access to foreign libraries), you will need to also install 52 | the `ctypes-foreign` optional dependency: 53 | 54 | opam install ctypes ctypes-foreign 55 | 56 | This will make the `ctypes.foreign` ocamlfind subpackage available.""" 57 | authors: "yallop@gmail.com" 58 | flags: light-uninstall 59 | url { 60 | src: "https://github.com/ocamllabs/ocaml-ctypes/archive/0.14.0.tar.gz" 61 | checksum: "md5=57875f5e5986ca6004c356d77a3b31b5" 62 | } 63 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/dune.1.7.3/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "opensource@janestreet.com" 3 | authors: ["Jane Street Group, LLC "] 4 | homepage: "https://github.com/ocaml/dune" 5 | bug-reports: "https://github.com/ocaml/dune/issues" 6 | dev-repo: "git+https://github.com/ocaml/dune.git" 7 | license: "MIT" 8 | depends: [ 9 | "ocaml" {>= "4.02"} 10 | "base-unix" 11 | "base-threads" 12 | ] 13 | build: [ 14 | # opam 2 sets OPAM_SWITCH_PREFIX, so we don't need a hardcoded path 15 | ["ocaml" "configure.ml" "--libdir" lib] {opam-version < "2"} 16 | ["ocaml" "bootstrap.ml"] 17 | ["./boot.exe" "--release" "--subst"] {pinned} 18 | ["./boot.exe" "--release" "-j" jobs] 19 | ] 20 | conflicts: [ 21 | "jbuilder" {!= "transition"} 22 | "odoc" {< "1.3.0"} 23 | ] 24 | 25 | synopsis: "Fast, portable and opinionated build system" 26 | description: """ 27 | dune is a build system that was designed to simplify the release of 28 | Jane Street packages. It reads metadata from "dune" files following a 29 | very simple s-expression syntax. 30 | 31 | dune is fast, it has very low-overhead and support parallel builds on 32 | all platforms. It has no system dependencies, all you need to build 33 | dune and packages using dune is OCaml. You don't need or make or bash 34 | as long as the packages themselves don't use bash explicitly. 35 | 36 | dune supports multi-package development by simply dropping multiple 37 | repositories into the same directory. 38 | 39 | It also supports multi-context builds, such as building against 40 | several opam roots/switches simultaneously. This helps maintaining 41 | packages across several versions of OCaml and gives cross-compilation 42 | for free. 43 | """ 44 | url { 45 | src: "https://github.com/ocaml/dune/releases/download/1.7.3/dune-1.7.3.tbz" 46 | checksum: "md5=644f0c1419d70b9daccac4b4e5664523" 47 | } 48 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/easy-format.1.3.1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | homepage: "http://mjambon.com/easy-format.html" 5 | bug-reports: "https://github.com/mjambon/easy-format/issues" 6 | dev-repo: "git+https://github.com/mjambon/easy-format.git" 7 | build: [ 8 | ["jbuilder" "build" "-p" name "-j" jobs] 9 | ["jbuilder" "runtest" "-p" name] {with-test} 10 | ] 11 | depends: [ 12 | "ocaml" {>= "4.02.3"} 13 | "jbuilder" {build} 14 | ] 15 | synopsis: 16 | "High-level and functional interface to the Format module of the OCaml standard library" 17 | url { 18 | src: "https://github.com/mjambon/easy-format/archive/v1.3.1.tar.gz" 19 | checksum: "md5=4e163700fb88fdcd6b8976c3a216c8ea" 20 | } 21 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/fmt.0.8.5/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: [ 4 | "Daniel Bünzli " 5 | "Gabriel Radanne" 6 | ] 7 | homepage: "http://erratique.ch/software/fmt" 8 | doc: "http://erratique.ch/software/fmt" 9 | dev-repo: "git+http://erratique.ch/repos/fmt.git" 10 | bug-reports: "https://github.com/dbuenzli/fmt/issues" 11 | tags: [ "string" "format" "pretty-print" "org:erratique" ] 12 | license: "ISC" 13 | depends: [ 14 | "ocaml" {>= "4.01.0"} 15 | "ocamlfind" {build} 16 | "ocamlbuild" {build} 17 | "topkg" {build & >= "0.9.0"} 18 | "result" 19 | "uchar" 20 | ] 21 | depopts: [ "base-unix" "cmdliner" ] 22 | conflicts: [ "cmdliner" {< "0.9.8"} ] 23 | build: [[ 24 | "ocaml" "pkg/pkg.ml" "build" 25 | "--dev-pkg" "%{pinned}%" 26 | "--with-base-unix" "%{base-unix:installed}%" 27 | "--with-cmdliner" "%{cmdliner:installed}%" ]] 28 | synopsis: "OCaml Format pretty-printer combinators" 29 | description: """ 30 | Fmt exposes combinators to devise `Format` pretty-printing functions. 31 | 32 | Fmt depends only on the OCaml standard library. The optional `Fmt_tty` 33 | library that allows to setup formatters for terminal color output 34 | depends on the Unix library. The optional `Fmt_cli` library that 35 | provides command line support for Fmt depends on [`Cmdliner`][cmdliner]. 36 | 37 | Fmt is distributed under the ISC license. 38 | 39 | [cmdliner]: http://erratique.ch/software/cmdliner""" 40 | url { 41 | src: "http://erratique.ch/software/fmt/releases/fmt-0.8.5.tbz" 42 | checksum: "md5=77b64aa6f20f09de28f2405d6195f12c" 43 | } 44 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/integers.0.2.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "yallop@gmail.com" 3 | authors: ["Jeremy Yallop" 4 | "Demi Obenour" 5 | "Stephane Glondu" 6 | "Andreas Hauptmann"] 7 | homepage: "https://github.com/ocamllabs/ocaml-integers" 8 | bug-reports: "https://github.com/ocamllabs/ocaml-integers/issues" 9 | dev-repo: "git+https://github.com/ocamllabs/ocaml-integers.git" 10 | license: "MIT" 11 | build: 12 | [[ "ocaml" "pkg/pkg.ml" "build" 13 | "--pinned" "%{pinned}%"]] 14 | depends: [ 15 | "ocaml" 16 | "ocamlbuild" {build} 17 | "ocamlfind" {build} 18 | "topkg" {build} 19 | ] 20 | doc: "http://ocamllabs.github.io/ocaml-integers/api.docdir/" 21 | synopsis: "Various signed and unsigned integer types for OCaml" 22 | url { 23 | src: 24 | "https://github.com/ocamllabs/ocaml-integers/releases/download/v0.2.2/integers-0.2.2.tbz" 25 | checksum: "md5=ae226532930965fe0b43c02f2469cadc" 26 | } 27 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/jbuilder.transition/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "opensource@janestreet.com" 3 | authors: ["Jane Street Group, LLC "] 4 | homepage: "https://github.com/ocaml/dune" 5 | bug-reports: "https://github.com/ocaml/dune/issues" 6 | dev-repo: "git+https://github.com/ocaml/dune.git" 7 | license: "MIT" 8 | depends: ["ocaml" "dune"] 9 | post-messages: [ 10 | "Jbuilder has been renamed and the jbuilder package is now a transition \ 11 | package. Use the dune package instead." 12 | ] 13 | synopsis: 14 | "This is a transition package, jbuilder is now named dune. Use the dune" 15 | description: "package instead." 16 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/logs.0.6.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/logs" 5 | doc: "http://erratique.ch/software/logs/doc" 6 | dev-repo: "git+http://erratique.ch/repos/logs.git" 7 | bug-reports: "https://github.com/dbuenzli/logs/issues" 8 | tags: [ "log" "system" "org:erratique" ] 9 | license: "ISC" 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {build} 14 | "topkg" {build} 15 | "result" 16 | "mtime" {with-test} 17 | ] 18 | depopts: [ 19 | "js_of_ocaml" 20 | "fmt" 21 | "cmdliner" 22 | "lwt" ] 23 | conflicts: [ "cmdliner" {< "0.9.8"} ] 24 | build: [[ 25 | "ocaml" "pkg/pkg.ml" "build" 26 | "--pinned" "%{pinned}%" 27 | "--with-js_of_ocaml" "%{js_of_ocaml:installed}%" 28 | "--with-fmt" "%{fmt:installed}%" 29 | "--with-cmdliner" "%{cmdliner:installed}%" 30 | "--with-lwt" "%{lwt:installed}%" ]] 31 | synopsis: "Logging infrastructure for OCaml" 32 | description: """ 33 | Logs provides a logging infrastructure for OCaml. Logging is performed 34 | on sources whose reporting level can be set independently. Log message 35 | report is decoupled from logging and is handled by a reporter. 36 | 37 | A few optional log reporters are distributed with the base library and 38 | the API easily allows to implement your own. 39 | 40 | `Logs` depends only on the `result` compatibility package. The 41 | optional `Logs_fmt` reporter on OCaml formatters depends on [Fmt][fmt]. 42 | The optional `Logs_browser` reporter that reports to the web browser 43 | console depends on [js_of_ocaml][jsoo]. The optional `Logs_cli` library 44 | that provides command line support for controlling Logs depends on 45 | [`Cmdliner`][cmdliner]. The optional `Logs_lwt` library that provides Lwt logging 46 | functions depends on [`Lwt`][lwt] 47 | 48 | Logs and its reporters are distributed under the ISC license. 49 | 50 | [fmt]: http://erratique.ch/software/fmt 51 | [jsoo]: http://ocsigen.org/js_of_ocaml/ 52 | [cmdliner]: http://erratique.ch/software/cmdliner 53 | [lwt]: http://ocsigen.org/lwt/""" 54 | url { 55 | src: "http://erratique.ch/software/logs/releases/logs-0.6.2.tbz" 56 | checksum: "md5=19f824c02c83c6dddc3bfb6459e4743e" 57 | } 58 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/lwt.4.1.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | version: "4.1.0" 3 | maintainer: [ 4 | "Anton Bachin " 5 | "Mauricio Fernandez " 6 | "Simon Cruanes " 7 | ] 8 | authors: [ 9 | "Jérôme Vouillon" 10 | "Jérémie Dimino" 11 | ] 12 | homepage: "https://github.com/ocsigen/lwt" 13 | doc: "https://ocsigen.org/lwt/manual/" 14 | bug-reports: "https://github.com/ocsigen/lwt/issues" 15 | license: "LGPL with OpenSSL linking exception" 16 | dev-repo: "git+https://github.com/ocsigen/lwt.git" 17 | build: [ 18 | [ "ocaml" "src/util/configure.ml" "-use-libev" "%{conf-libev:installed}%" ] 19 | [ "jbuilder" "build" "-p" name "-j" jobs ] 20 | ] 21 | 22 | depends: [ 23 | "ocaml" {>= "4.02.0"} 24 | "cppo" {build & >= "1.1.0"} 25 | "jbuilder" {build & >= "1.0+beta14"} 26 | "ocamlfind" {build & >= "1.7.3-1"} 27 | "result" 28 | ] 29 | depopts: [ 30 | "base-threads" 31 | "base-unix" 32 | "conf-libev" 33 | ] 34 | # In practice, Lwt requires OCaml >= 4.02.3, as that is a constraint of the 35 | # dependency jbuilder. 36 | messages: [ 37 | "For the PPX, please install package lwt_ppx" 38 | {!lwt_ppx:installed} 39 | "For the Camlp4 syntax, please install package lwt_camlp4" 40 | {camlp4:installed & !lwt_camlp4:installed} 41 | "For Lwt_log and Lwt_daemon, please install package lwt_log" 42 | {!lwt_log:installed} 43 | ] 44 | synopsis: "Promises, concurrency, and parallelized I/O" 45 | description: """ 46 | A promise is a value that may become determined in the future. 47 | 48 | Lwt provides typed, composable promises. Promises that are resolved by I/O are 49 | resolved by Lwt in parallel. 50 | 51 | Meanwhile, OCaml code, including code creating and waiting on promises, runs in 52 | a single thread by default. This reduces the need for locks or other 53 | synchronization primitives. Code can be run in parallel on an opt-in basis.""" 54 | conflicts: [ 55 | "ocaml-variants" {= "4.02.1+BER"} 56 | ] 57 | url { 58 | src: "https://github.com/ocsigen/lwt/archive/4.1.0.tar.gz" 59 | checksum: "md5=e919bee206f18b3d49250ecf9584fde7" 60 | } 61 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/menhir.20181113/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "francois.pottier@inria.fr" 3 | authors: [ 4 | "François Pottier " 5 | "Yann Régis-Gianas " 6 | ] 7 | homepage: "http://gitlab.inria.fr/fpottier/menhir" 8 | dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git" 9 | bug-reports: "menhir@inria.fr" 10 | build: [ 11 | [make "-f" "Makefile" "PREFIX=%{prefix}%" "USE_OCAMLFIND=true" "docdir=%{doc}%/menhir" "libdir=%{lib}%/menhir" "mandir=%{man}%/man1"] 12 | ] 13 | install: [ 14 | [make "-f" "Makefile" "install" "PREFIX=%{prefix}%" "docdir=%{doc}%/menhir" "libdir=%{lib}%/menhir" "mandir=%{man}%/man1"] 15 | ] 16 | remove: [ 17 | [make "-f" "Makefile" "uninstall" "PREFIX=%{prefix}%" "docdir=%{doc}%/menhir" "libdir=%{lib}%/menhir" "mandir=%{man}%/man1"] 18 | ] 19 | depends: [ 20 | "ocaml" {>= "4.02"} 21 | "ocamlfind" {build} 22 | "ocamlbuild" {build} 23 | ] 24 | synopsis: "An LR(1) parser generator" 25 | url { 26 | src: 27 | "https://gitlab.inria.fr/fpottier/menhir/repository/20181113/archive.tar.gz" 28 | checksum: [ 29 | "md5=69ce441a06ea131cd43e7b44c4303f3c" 30 | "sha512=4ddefcd71d305bfb933a4056da57e36c13c99ec6dfcc4695814798fbbd78b4d65828381ebcb0e58c4c0394105ac763af3d475474e05e408f7080315bc3cf6176" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/merlin-extend.0.3/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Frederic Bour " 3 | authors: "Frederic Bour " 4 | homepage: "https://github.com/let-def/merlin-extend" 5 | bug-reports: "https://github.com/let-def/merlin-extend" 6 | license: "MIT" 7 | dev-repo: "git+https://github.com/let-def/merlin-extend.git" 8 | build: [make] 9 | install: [make "install"] 10 | remove: ["ocamlfind" "remove" "merlin_extend"] 11 | depends: [ 12 | "ocaml" {>= "4.02.3"} 13 | "ocamlfind" {build} 14 | "cppo" {build} 15 | ] 16 | synopsis: "A protocol to provide custom frontend to Merlin" 17 | description: """ 18 | This protocol allows to replace the OCaml frontend of Merlin. 19 | It extends what used to be done with the `-pp' flag to handle a few more cases.""" 20 | flags: light-uninstall 21 | url { 22 | src: "https://github.com/let-def/merlin-extend/archive/v0.3.tar.gz" 23 | checksum: "md5=9c6dfd4f53328f02f12fcc265f4e2dda" 24 | } 25 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/merlin.3.2.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | name: "merlin" 3 | synopsis: "Installation with Opam" 4 | description: """ 5 | If you have a working [Opam](https://opam.ocaml.org/) installation, Merlin is only two commands away: 6 | 7 | ```shell 8 | opam install merlin 9 | opam user-setup install 10 | ``` 11 | 12 | [opam-user-setup](https://github.com/OCamlPro/opam-user-setup) takes care of configuring Emacs and Vim to make best use of your current install. 13 | 14 | You can also [configure the editor](#editor-setup) yourself, if you prefer.""" 15 | maintainer: "defree@gmail.com" 16 | authors: "The Merlin team" 17 | homepage: "https://github.com/ocaml/merlin" 18 | bug-reports: "https://github.com/ocaml/merlin/issues" 19 | depends: [ 20 | "ocaml" {>= "4.02.1" & < "4.08"} 21 | "dune" {build} 22 | "ocamlfind" {>= "1.5.2"} 23 | "yojson" 24 | "craml" {with-test} 25 | ] 26 | build: [ 27 | ["dune" "subst"] {pinned} 28 | ["dune" "build" "-p" name "-j" jobs] 29 | ] 30 | post-messages: 31 | """ 32 | merlin installed. 33 | 34 | Quick setup for VIM 35 | ------------------- 36 | Append this to your .vimrc to add merlin to vim's runtime-path: 37 | let g:opamshare = substitute(system('opam config var share'),'\\n$','','''') 38 | execute "set rtp+=" . g:opamshare . "/merlin/vim" 39 | 40 | Also run the following line in vim to index the documentation: 41 | :execute "helptags " . g:opamshare . "/merlin/vim/doc" 42 | 43 | Quick setup for EMACS 44 | ------------------- 45 | Add opam emacs directory to your load-path by appending this to your .emacs: 46 | (let ((opam-share (ignore-errors (car (process-lines "opam" "config" "var" "share"))))) 47 | (when (and opam-share (file-directory-p opam-share)) 48 | ;; Register Merlin 49 | (add-to-list 'load-path (expand-file-name "emacs/site-lisp" opam-share)) 50 | (autoload 'merlin-mode "merlin" nil t nil) 51 | ;; Automatically start it in OCaml buffers 52 | (add-hook 'tuareg-mode-hook 'merlin-mode t) 53 | (add-hook 'caml-mode-hook 'merlin-mode t) 54 | ;; Use opam switch to lookup ocamlmerlin binary 55 | (setq merlin-command 'opam))) 56 | 57 | Take a look at https://github.com/ocaml/merlin for more information 58 | 59 | Quick setup with opam-user-setup 60 | -------------------------------- 61 | 62 | Opam-user-setup support Merlin. 63 | 64 | $ opam user-setup install 65 | 66 | should take care of basic setup. 67 | See https://github.com/OCamlPro/opam-user-setup""" 68 | {success & !user-setup:installed} 69 | dev-repo: "git+https://github.com/ocaml/merlin.git" 70 | url { 71 | src: 72 | "https://github.com/ocaml/merlin/releases/download/v3.2.2/merlin-v3.2.2.tbz" 73 | checksum: "md5=ede35b65f8ac9c440cfade5445662c54" 74 | } 75 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ocaml-migrate-parsetree.1.2.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "frederic.bour@lakaban.net" 3 | authors: [ 4 | "Frédéric Bour " 5 | "Jérémie Dimino " 6 | ] 7 | license: "LGPL-2.1" 8 | homepage: "https://github.com/ocaml-ppx/ocaml-migrate-parsetree" 9 | bug-reports: "https://github.com/ocaml-ppx/ocaml-migrate-parsetree/issues" 10 | dev-repo: "git+https://github.com/ocaml-ppx/ocaml-migrate-parsetree.git" 11 | doc: "https://ocaml-ppx.github.io/ocaml-migrate-parsetree/" 12 | tags: [ "syntax" "org:ocamllabs" ] 13 | build: [ 14 | ["dune" "build" "-p" name "-j" jobs] 15 | ] 16 | depends: [ 17 | "result" 18 | "ppx_derivers" 19 | "dune" {build & >= "1.6.0"} 20 | "ocaml" {>= "4.02.3"} 21 | ] 22 | synopsis: "Convert OCaml parsetrees between different versions" 23 | description: """ 24 | Convert OCaml parsetrees between different versions 25 | 26 | This library converts parsetrees, outcometree and ast mappers between 27 | different OCaml versions. High-level functions help making PPX 28 | rewriters independent of a compiler version. 29 | """ 30 | url { 31 | src: 32 | "https://github.com/ocaml-ppx/ocaml-migrate-parsetree/releases/download/v1.2.0/ocaml-migrate-parsetree-v1.2.0.tbz" 33 | checksum: "md5=cc6fb09ad6f99156c7dba47711c62c6f" 34 | } 35 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ocamlbuild.0.14.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Gabriel Scherer " 3 | authors: ["Nicolas Pouillard" "Berke Durak"] 4 | homepage: "https://github.com/ocaml/ocamlbuild/" 5 | bug-reports: "https://github.com/ocaml/ocamlbuild/issues" 6 | license: "LGPL-2 with OCaml linking exception" 7 | doc: "https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc" 8 | dev-repo: "git+https://github.com/ocaml/ocamlbuild.git" 9 | build: [ 10 | [ 11 | make 12 | "-f" 13 | "configure.make" 14 | "all" 15 | "OCAMLBUILD_PREFIX=%{prefix}%" 16 | "OCAMLBUILD_BINDIR=%{bin}%" 17 | "OCAMLBUILD_LIBDIR=%{lib}%" 18 | "OCAMLBUILD_MANDIR=%{man}%" 19 | "OCAML_NATIVE=%{ocaml:native}%" 20 | "OCAML_NATIVE_TOOLS=%{ocaml:native}%" 21 | ] 22 | [make "check-if-preinstalled" "all" "opam-install"] 23 | ] 24 | conflicts: [ 25 | "base-ocamlbuild" 26 | "ocamlfind" {< "1.6.2"} 27 | ] 28 | synopsis: 29 | "OCamlbuild is a build system with builtin rules to easily build most OCaml projects." 30 | depends: [ 31 | "ocaml" {>= "4.03"} 32 | ] 33 | url { 34 | src: "https://github.com/ocaml/ocamlbuild/archive/0.14.0.tar.gz" 35 | checksum: "sha256=87b29ce96958096c0a1a8eeafeb6268077b2d11e1bf2b3de0f5ebc9cf8d42e78" 36 | } 37 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ocamlfind.1.8.0/files/ocaml-stub: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BINDIR=$(dirname "$(command -v ocamlc)") 4 | "$BINDIR/ocaml" -I "$OCAML_TOPLEVEL_PATH" "$@" 5 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ocamlfind.1.8.0/files/ocamlfind.install: -------------------------------------------------------------------------------- 1 | bin: [ 2 | "src/findlib/ocamlfind" {"ocamlfind"} 3 | "?src/findlib/ocamlfind_opt" {"ocamlfind"} 4 | "?tools/safe_camlp4" 5 | ] 6 | toplevel: ["src/findlib/topfind"] 7 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ocamlfind.1.8.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Thomas Gazagnaire " 3 | homepage: "http://projects.camlcity.org/projects/findlib.html" 4 | bug-reports: "https://gitlab.camlcity.org/gerd/lib-findlib/issues" 5 | dev-repo: "git+https://gitlab.camlcity.org/gerd/lib-findlib.git" 6 | build: [ 7 | [ 8 | "./configure" 9 | "-bindir" 10 | bin 11 | "-sitelib" 12 | lib 13 | "-mandir" 14 | man 15 | "-config" 16 | "%{lib}%/findlib.conf" 17 | "-no-custom" 18 | "-no-topfind" {ocaml:preinstalled} 19 | ] 20 | [make "all"] 21 | [make "opt"] {ocaml:native} 22 | ] 23 | install: [ 24 | [make "install"] 25 | ["install" "-m" "0755" "ocaml-stub" "%{bin}%/ocaml"] {ocaml:preinstalled} 26 | ] 27 | remove: [ 28 | ["ocamlfind" "remove" "bytes"] 29 | [ 30 | "./configure" 31 | "-bindir" 32 | bin 33 | "-sitelib" 34 | lib 35 | "-mandir" 36 | man 37 | "-config" 38 | "%{lib}%/findlib.conf" 39 | "-no-topfind" {ocaml:preinstalled} 40 | ] 41 | [make "uninstall"] 42 | ["rm" "-f" "%{bin}%/ocaml"] {ocaml:preinstalled} 43 | ] 44 | depends: [ 45 | "ocaml" {>= "4.00.0"} 46 | "conf-m4" {build} 47 | ] 48 | synopsis: "A library manager for OCaml" 49 | description: """ 50 | Findlib is a library manager for OCaml. It provides a convention how 51 | to store libraries, and a file format ("META") to describe the 52 | properties of libraries. There is also a tool (ocamlfind) for 53 | interpreting the META files, so that it is very easy to use libraries 54 | in programs and scripts.""" 55 | authors: "Gerd Stolpmann " 56 | extra-files: [ 57 | ["ocamlfind.install" "md5=06f2c282ab52d93aa6adeeadd82a2543"] 58 | ["ocaml-stub" "md5=181f259c9e0bad9ef523e7d4abfdf87a"] 59 | ] 60 | url { 61 | src: "http://download.camlcity.org/download/findlib-1.8.0.tar.gz" 62 | checksum: "md5=a710c559667672077a93d34eb6a42e5b" 63 | mirrors: "http://download2.camlcity.org/download/findlib-1.8.0.tar.gz" 64 | } 65 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ocb-stubblr.0.1.1-1/files/custom-cclib.patch: -------------------------------------------------------------------------------- 1 | From d51b3f3a49f159469e00d23524db915f19bb0127 Mon Sep 17 00:00:00 2001 2 | From: Hannes Mehnert 3 | Date: Tue, 3 Oct 2017 13:55:16 +0100 4 | Subject: [PATCH] bytecode / custom needs -cclib as well 5 | 6 | --- 7 | src/ocb_stubblr.ml | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/src/ocb_stubblr.ml b/src/ocb_stubblr.ml 11 | index b68c37a..a0ee035 100644 12 | --- a/src/ocb_stubblr.ml 13 | +++ b/src/ocb_stubblr.ml 14 | @@ -160,7 +160,7 @@ let link_flag () = 15 | S [A switch; A ("-l"^name)] 16 | and dep flag = Pathname.([remove_extension flag -.- "a"]) in 17 | pflag ["link"; "ocaml"; "library"; "byte"] tag (libarg "-dllib"); 18 | - pflag ["link"; "ocaml"; "library"; "native"] tag (libarg "-cclib"); 19 | + pflag ["link"; "ocaml"; "library"] tag (libarg "-cclib"); 20 | pdep ["link"; "ocaml"] tag dep; 21 | pdep ["compile"; "ocaml"] tag dep 22 | (* XXX sneak in '-I' for compile;ocaml;program ?? *) 23 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ocb-stubblr.0.1.1-1/files/use-OPAM_SWITCH_PREFIX.patch: -------------------------------------------------------------------------------- 1 | From f1c9340f3ab973ad1e8dcc4b7065bbe6cfaa028f Mon Sep 17 00:00:00 2001 2 | From: David Allsopp 3 | Date: Sun, 1 Jul 2018 09:54:32 +0100 4 | Subject: [PATCH] Use OPAM_SWITCH_PREFIX before opam config var prefix 5 | 6 | opam 2's sandbox doesn't expose the mount point for the opam root. 7 | 8 | Signed-off-by: David Allsopp 9 | --- 10 | src/ocb_stubblr.ml | 6 +++++- 11 | 1 file changed, 5 insertions(+), 1 deletion(-) 12 | 13 | diff --git a/src/ocb_stubblr.ml b/src/ocb_stubblr.ml 14 | index b68c37a..2cc5332 100644 15 | --- a/src/ocb_stubblr.ml 16 | +++ b/src/ocb_stubblr.ml 17 | @@ -31,11 +31,15 @@ module Pkg_config = struct 18 | 19 | (* XXX Would be nice to move pkg-config results to a build artefact. *) 20 | 21 | - let opam_prefix = 22 | + let opam_prefix_cmd = 23 | let cmd = "opam config var prefix" in 24 | lazy ( try run_and_read cmd with Failure _ -> 25 | error_msgf "error running opam") 26 | 27 | + let opam_prefix = 28 | + lazy (try Sys.getenv "OPAM_SWITCH_PREFIX" 29 | + with Not_found -> Lazy.force opam_prefix_cmd) 30 | + 31 | let var = "PKG_CONFIG_PATH" 32 | 33 | let path () = 34 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/ocb-stubblr.0.1.1-1/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "David Kaloper Meršinjak " 3 | authors: ["David Kaloper Meršinjak "] 4 | homepage: "https://github.com/pqwy/ocb-stubblr" 5 | doc: "https://pqwy.github.io/ocb-stubblr/doc" 6 | license: "ISC" 7 | dev-repo: "git+https://github.com/pqwy/ocb-stubblr.git" 8 | bug-reports: "https://github.com/pqwy/ocb-stubblr/issues" 9 | tags: ["ocamlbuild"] 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build} 13 | "ocamlbuild" {>= "0.9.3" | < "0.9.0"} 14 | "topkg" {>= "0.8.1"} 15 | "astring" 16 | ] 17 | build: [ "ocaml" "pkg/pkg.ml" "build" "--pinned" "%{pinned}%" "--tests" "false" ] 18 | 19 | patches: [ 20 | "custom-cclib.patch" 21 | "use-OPAM_SWITCH_PREFIX.patch" 22 | ] 23 | 24 | synopsis: "OCamlbuild plugin for C stubs" 25 | description: """ 26 | Do you get excited by C stubs? Do they sometimes make you swoon, and even faint, 27 | and in the end no `cmxa`s get properly linked -- not to mention correct 28 | multi-lib support? 29 | 30 | Do you wish that the things that excite you the most, would excite you just a 31 | little less? Then ocb-stubblr is just the library for you. 32 | 33 | ocb-stubblr is about ten lines of code that you need to repeat over, over, over 34 | and over again if you are using `ocamlbuild` to build OCaml projects that 35 | contain C stubs -- now with 100% more lib! 36 | 37 | It does what everyone wants to do with `.clib` files in their project 38 | directories. It can also clone the `.clib` and arrange for multiple compilations 39 | with different sets of discovered `cflags`. 40 | 41 | ocb-stubblr is distributed under the ISC license.""" 42 | url { 43 | src: 44 | "https://github.com/pqwy/ocb-stubblr/releases/download/v0.1.1/ocb-stubblr-0.1.1.tbz" 45 | checksum: "md5=607720dd18ca51e40645b42df5c1273e" 46 | } 47 | extra-files: [ 48 | [ 49 | "custom-cclib.patch" 50 | "md5=d479b52a50d53dd79da2d6eea2a9a9e3" 51 | ] 52 | [ 53 | "use-OPAM_SWITCH_PREFIX.patch" 54 | "md5=a7271bb1f862bd3da4ffd9caa87ca76f" 55 | ] 56 | ] -------------------------------------------------------------------------------- /examples/esy.lock/opam/ppx_derivers.1.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "jeremie@dimino.org" 3 | authors: ["Jérémie Dimino"] 4 | license: "BSD3" 5 | homepage: "https://github.com/ocaml-ppx/ppx_derivers" 6 | bug-reports: "https://github.com/ocaml-ppx/ppx_derivers/issues" 7 | dev-repo: "git://github.com/ocaml-ppx/ppx_derivers.git" 8 | build: [ 9 | ["jbuilder" "build" "-p" name "-j" jobs] 10 | ] 11 | depends: [ 12 | "ocaml" 13 | "jbuilder" {build & >= "1.0+beta7"} 14 | ] 15 | synopsis: "Shared [@@deriving] plugin registry" 16 | description: """ 17 | Ppx_derivers is a tiny package whose sole purpose is to allow 18 | ppx_deriving and ppx_type_conv to inter-operate gracefully when linked 19 | as part of the same ocaml-migrate-parsetree driver.""" 20 | url { 21 | src: "https://github.com/ocaml-ppx/ppx_derivers/archive/1.0.tar.gz" 22 | checksum: "md5=4ddce8f43fdb9b0ef0ab6a7cbfebc3e3" 23 | } 24 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/re.1.8.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "rudi.grinberg@gmail.com" 3 | authors: [ 4 | "Jerome Vouillon" 5 | "Thomas Gazagnaire" 6 | "Anil Madhavapeddy" 7 | "Rudi Grinberg" 8 | "Gabriel Radanne" 9 | ] 10 | license: "LGPL-2.0 with OCaml linking exception" 11 | homepage: "https://github.com/ocaml/ocaml-re" 12 | bug-reports: "https://github.com/ocaml/ocaml-re/issues" 13 | dev-repo: "git+https://github.com/ocaml/ocaml-re.git" 14 | build: [ 15 | ["jbuilder" "subst" "-n" name] {pinned} 16 | ["jbuilder" "build" "-p" name "-j" jobs] 17 | ["jbuilder" "runtest" "-p" name "-j" jobs] {with-test} 18 | ] 19 | depends: [ 20 | "ocaml" {>= "4.02.3"} 21 | "jbuilder" {build & >= "1.0+beta10"} 22 | "ounit" {with-test} 23 | "seq" 24 | ] 25 | synopsis: "RE is a regular expression library for OCaml" 26 | description: """ 27 | Pure OCaml regular expressions with: 28 | * Perl-style regular expressions (module Re.Perl) 29 | * Posix extended regular expressions (module Re.Posix) 30 | * Emacs-style regular expressions (module Re.Emacs) 31 | * Shell-style file globbing (module Re.Glob) 32 | * Compatibility layer for OCaml's built-in Str module (module Re.Str)""" 33 | url { 34 | src: 35 | "https://github.com/ocaml/ocaml-re/releases/download/1.8.0/re-1.8.0.tbz" 36 | checksum: "md5=765f6f8d3e6ab200866e719ed7e5178d" 37 | } 38 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/reason.3.4.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Jordan Walke " 3 | authors: [ "Jordan Walke " ] 4 | license: "MIT" 5 | homepage: "https://github.com/facebook/reason" 6 | doc: "http://reasonml.github.io/" 7 | bug-reports: "https://github.com/facebook/reason/issues" 8 | dev-repo: "git://github.com/facebook/reason.git" 9 | tags: [ "syntax" ] 10 | build: [ 11 | ["dune" "build" "-p" name "-j" jobs] 12 | ["dune" "runtest" "-p" name "-j" jobs] {with-test} 13 | ] 14 | depends: [ 15 | "ocaml" {>= "4.02" & < "4.08"} 16 | "dune" {build & >= "1.4"} 17 | "ocamlfind" {build} 18 | "menhir" {>= "20170418"} 19 | "merlin-extend" {>= "0.3"} 20 | "result" 21 | "ocaml-migrate-parsetree" 22 | ] 23 | synopsis: "Reason: Syntax & Toolchain for OCaml" 24 | description: """ 25 | Reason gives OCaml a new syntax that is remniscient of languages like 26 | JavaScript. It's also the umbrella project for a set of tools for the OCaml & 27 | JavaScript ecosystem.""" 28 | url { 29 | src: "https://registry.npmjs.org/@esy-ocaml/reason/-/reason-3.4.0.tgz" 30 | checksum: "md5=1b6cba03588e5fba3b5eb693c0d02dea" 31 | } 32 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/result.1.3/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "opensource@janestreet.com" 3 | authors: ["Jane Street Group, LLC "] 4 | homepage: "https://github.com/janestreet/result" 5 | dev-repo: "git+https://github.com/janestreet/result.git" 6 | bug-reports: "https://github.com/janestreet/result/issues" 7 | license: "BSD3" 8 | build: [["jbuilder" "build" "-p" name "-j" jobs]] 9 | depends: [ 10 | "ocaml" 11 | "jbuilder" {build & >= "1.0+beta11"} 12 | ] 13 | synopsis: "Compatibility Result module" 14 | description: """ 15 | Projects that want to use the new result type defined in OCaml >= 4.03 16 | while staying compatible with older version of OCaml should use the 17 | Result module defined in this library.""" 18 | url { 19 | src: 20 | "https://github.com/janestreet/result/releases/download/1.3/result-1.3.tbz" 21 | checksum: "md5=4beebefd41f7f899b6eeba7414e7ae01" 22 | } 23 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/seq.base/files/META.seq: -------------------------------------------------------------------------------- 1 | name="seq" 2 | version="[distributed with OCaml 4.07 or above]" 3 | description="dummy backward-compatibility package for iterators" 4 | requires="" 5 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/seq.base/files/seq.install: -------------------------------------------------------------------------------- 1 | lib:[ 2 | "META.seq" {"META"} 3 | ] 4 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/seq.base/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: " " 3 | authors: " " 4 | homepage: " " 5 | depends: [ 6 | "ocaml" {>= "4.07.0"} 7 | ] 8 | dev-repo: "git+https://github.com/ocaml/ocaml.git" 9 | bug-reports: "https://caml.inria.fr/mantis/main_page.php" 10 | synopsis: 11 | "Compatibility package for OCaml's standard iterator type starting from 4.07." 12 | extra-files: [ 13 | ["seq.install" "md5=026b31e1df290373198373d5aaa26e42"] 14 | ["META.seq" "md5=b33c8a1a6c7ed797816ce27df4855107"] 15 | ] 16 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/topkg.1.0.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://erratique.ch/software/topkg" 5 | doc: "http://erratique.ch/software/topkg/doc" 6 | license: "ISC" 7 | dev-repo: "git+http://erratique.ch/repos/topkg.git" 8 | bug-reports: "https://github.com/dbuenzli/topkg/issues" 9 | tags: ["packaging" "ocamlbuild" "org:erratique"] 10 | depends: [ 11 | "ocaml" {>= "4.01.0"} 12 | "ocamlfind" {build & >= "1.6.1"} 13 | "ocamlbuild" 14 | "result" ] 15 | build: [[ 16 | "ocaml" "pkg/pkg.ml" "build" 17 | "--pkg-name" name 18 | "--dev-pkg" "%{pinned}%" ]] 19 | synopsis: """The transitory OCaml software packager""" 20 | description: """\ 21 | 22 | Topkg is a packager for distributing OCaml software. It provides an 23 | API to describe the files a package installs in a given build 24 | configuration and to specify information about the package's 25 | distribution, creation and publication procedures. 26 | 27 | The optional topkg-care package provides the `topkg` command line tool 28 | which helps with various aspects of a package's life cycle: creating 29 | and linting a distribution, releasing it on the WWW, publish its 30 | documentation, add it to the OCaml opam repository, etc. 31 | 32 | Topkg is distributed under the ISC license and has **no** 33 | dependencies. This is what your packages will need as a *build* 34 | dependency. 35 | 36 | Topkg-care is distributed under the ISC license it depends on 37 | [fmt][fmt], [logs][logs], [bos][bos], [cmdliner][cmdliner], 38 | [webbrowser][webbrowser] and `opam-format`. 39 | 40 | [fmt]: http://erratique.ch/software/fmt 41 | [logs]: http://erratique.ch/software/logs 42 | [bos]: http://erratique.ch/software/bos 43 | [cmdliner]: http://erratique.ch/software/cmdliner 44 | [webbrowser]: http://erratique.ch/software/webbrowser 45 | """ 46 | url { 47 | src: "http://erratique.ch/software/topkg/releases/topkg-1.0.0.tbz" 48 | checksum: "md5=e3d76bda06bf68cb5853caf6627da603" 49 | } 50 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/tsdl.0.9.6/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["The tsdl programmers"] 4 | homepage: "http://erratique.ch/software/tsdl" 5 | doc: "http://erratique.ch/software/tsdl/doc/Tsdl" 6 | dev-repo: "git+http://erratique.ch/repos/tsdl.git" 7 | bug-reports: "https://github.com/dbuenzli/tsdl/issues" 8 | tags: [ "audio" "bindings" "graphics" "media" "opengl" "input" "hci" 9 | "org:erratique" ] 10 | license: "ISC" 11 | depends: [ 12 | "ocaml" {>= "4.02.0"} 13 | "ocamlfind" {build} 14 | "ocamlbuild" {build} 15 | "topkg" {build} 16 | "ocb-stubblr" {build} 17 | "conf-sdl2" 18 | "result" 19 | "ctypes" {>= "0.9.0"} 20 | "ctypes-foreign" 21 | ] 22 | build: [[ 23 | "ocaml" "pkg/pkg.ml" "build" 24 | "--pinned" "%{pinned}%" ]] 25 | synopsis: "Thin bindings to SDL for OCaml" 26 | description: """ 27 | Tsdl is an OCaml library providing thin bindings to the cross-platform 28 | SDL C library. 29 | 30 | Tsdl depends on the [SDL 2.0.6][sdl] C library (or later), 31 | [ocaml-ctypes][ctypes] and the `result` compatibility package. 32 | Tsdl is distributed under the ISC license. 33 | 34 | [sdl]: http://www.libsdl.org/ 35 | [ctypes]: https://github.com/ocamllabs/ocaml-ctypes""" 36 | url { 37 | src: "http://erratique.ch/software/tsdl/releases/tsdl-0.9.6.tbz" 38 | checksum: "md5=846afa7b1f0aad7be9bdaa6b484a90df" 39 | } 40 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/uchar.0.0.2/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Daniel Bünzli " 3 | authors: ["Daniel Bünzli "] 4 | homepage: "http://ocaml.org" 5 | doc: "https://ocaml.github.io/uchar/" 6 | dev-repo: "git+https://github.com/ocaml/uchar.git" 7 | bug-reports: "https://github.com/ocaml/uchar/issues" 8 | tags: [ "text" "character" "unicode" "compatibility" "org:ocaml.org" ] 9 | license: "typeof OCaml system" 10 | depends: [ 11 | "ocaml" {>= "3.12.0"} 12 | "ocamlbuild" {build} 13 | ] 14 | build: [ 15 | ["ocaml" "pkg/git.ml"] 16 | [ 17 | "ocaml" 18 | "pkg/build.ml" 19 | "native=%{ocaml:native}%" 20 | "native-dynlink=%{ocaml:native-dynlink}%" 21 | ] 22 | ] 23 | synopsis: "Compatibility library for OCaml's Uchar module" 24 | description: """ 25 | The `uchar` package provides a compatibility library for the 26 | [`Uchar`][1] module introduced in OCaml 4.03. 27 | 28 | The `uchar` package is distributed under the license of the OCaml 29 | compiler. See [LICENSE](LICENSE) for details. 30 | 31 | [1]: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Uchar.html""" 32 | url { 33 | src: 34 | "https://github.com/ocaml/uchar/releases/download/v0.0.2/uchar-0.0.2.tbz" 35 | checksum: "md5=c9ba2c738d264c420c642f7bb1cf4a36" 36 | } 37 | -------------------------------------------------------------------------------- /examples/esy.lock/opam/yojson.1.7.0/opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "martin@mjambon.com" 3 | authors: ["Martin Jambon"] 4 | homepage: "https://github.com/ocaml-community/yojson" 5 | bug-reports: "https://github.com/ocaml-community/yojson/issues" 6 | dev-repo: "git+https://github.com/ocaml-community/yojson.git" 7 | doc: "https://ocaml-community.github.io/yojson/" 8 | build: [ 9 | ["dune" "subst"] {pinned} 10 | ["dune" "build" "-p" name "-j" jobs] 11 | ] 12 | run-test: [["dune" "runtest" "-p" name "-j" jobs]] 13 | depends: [ 14 | "ocaml" {>= "4.02.3"} 15 | "dune" {build} 16 | "cppo" {build} 17 | "easy-format" 18 | "biniou" {>= "1.2.0"} 19 | "alcotest" {with-test & >= "0.8.5"} 20 | ] 21 | synopsis: 22 | "Yojson is an optimized parsing and printing library for the JSON format" 23 | description: """ 24 | Yojson is an optimized parsing and printing library for the JSON format. 25 | 26 | It addresses a few shortcomings of json-wheel including 2x speedup, 27 | polymorphic variants and optional syntax for tuples and variants. 28 | 29 | ydump is a pretty-printing command-line program provided with the 30 | yojson package. 31 | 32 | The program atdgen can be used to derive OCaml-JSON serializers and 33 | deserializers from type definitions.""" 34 | url { 35 | src: 36 | "https://github.com/ocaml-community/yojson/releases/download/1.7.0/yojson-1.7.0.tbz" 37 | checksum: "md5=b89d39ca3f8c532abe5f547ad3b8f84d" 38 | } 39 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__conf_pkg_config_opam__c__1.1_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "yarn-pkg-config": "esy-ocaml/yarn-pkg-config#d488cd9321cd5036bd36ec96744ce78c5d45fc49" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__conf_sdl2_opam__c__1_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@esy-ocaml/sdl2": "esy-ocaml/SDL-mirror#4c156f3b581296674a8e245bfaabdc0b8eb5e3c4", 4 | "@opam/conf-pkg-config": "*" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__ctypes_opam__c__0.14.0_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "exportedEnv": { 3 | "CAML_LD_LIBRARY_PATH": { 4 | "val": "#{self.lib / 'ctypes' : $CAML_LD_LIBRARY_PATH}", 5 | "scope": "global" 6 | } 7 | }, 8 | "dependencies": { 9 | "@esy-ocaml/libffi": "3.2.10" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__dune_opam__c__1.7.3_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "ocaml", 5 | "bootstrap.ml" 6 | ], 7 | [ 8 | "./boot.exe", 9 | "--release", 10 | "-j", 11 | "4" 12 | ] 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__merlin_extend_opam__c__0.3_opam_override/files/merlin-extend-winfix.patch: -------------------------------------------------------------------------------- 1 | --- ./extend_helper.ml 2 | +++ ./extend_helper.ml 3 | @@ -1,13 +1,6 @@ 4 | -(*pp cppo -V OCAML:`ocamlc -version` *) 5 | open Parsetree 6 | open Extend_protocol 7 | 8 | -#if OCAML_VERSION < (4, 3, 0) 9 | -# define CONST_STRING Asttypes.Const_string 10 | -#else 11 | -# define CONST_STRING Parsetree.Pconst_string 12 | -#endif 13 | - 14 | (** Default implementation for [Reader_def.print_outcome] using 15 | [Oprint] from compiler-libs *) 16 | let print_outcome_using_oprint ppf = function 17 | @@ -28,7 +21,7 @@ 18 | pstr_loc = Location.none; 19 | pstr_desc = Pstr_eval ({ 20 | pexp_loc = Location.none; 21 | - pexp_desc = Pexp_constant (CONST_STRING (msg, None)); 22 | + pexp_desc = Pexp_constant (Parsetree.Pconst_string (msg, None)); 23 | pexp_attributes = []; 24 | }, []); 25 | }] 26 | @@ -112,7 +105,7 @@ 27 | let msg = match payload with 28 | | PStr [{ 29 | pstr_desc = Pstr_eval ({ 30 | - pexp_desc = Pexp_constant (CONST_STRING (msg, _)); 31 | + pexp_desc = Pexp_constant (Parsetree.Pconst_string (msg, _)); 32 | }, _); 33 | }] -> msg 34 | | _ -> "Warning: extension produced an incorrect syntax-error node" 35 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__merlin_extend_opam__c__0.3_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "bash", 5 | "-c", 6 | "#{os == 'windows' ? 'patch -p1 < merlin-extend-winfix.patch' : 'true'}" 7 | ], 8 | [ 9 | "make" 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__ocamlbuild_opam__c__0.14.0_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "bash", 5 | "-c", 6 | "#{os == 'windows' ? 'patch -p1 < ocamlbuild-0.14.0.patch' : 'true'}" 7 | ], 8 | [ 9 | "make", 10 | "-f", 11 | "configure.make", 12 | "all", 13 | "OCAMLBUILD_PREFIX=#{self.install}", 14 | "OCAMLBUILD_BINDIR=#{self.bin}", 15 | "OCAMLBUILD_LIBDIR=#{self.lib}", 16 | "OCAMLBUILD_MANDIR=#{self.man}", 17 | "OCAMLBUILD_NATIVE=true", 18 | "OCAMLBUILD_NATIVE_TOOLS=true" 19 | ], 20 | [ 21 | "make", 22 | "check-if-preinstalled", 23 | "all", 24 | "#{os == 'windows' ? 'install' : 'opam-install'}" 25 | ] 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__ocamlfind_opam__c__1.8.0_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": [ 3 | [ 4 | "bash", 5 | "-c", 6 | "#{os == 'windows' ? 'patch -p1 < findlib-1.8.0.patch' : 'true'}" 7 | ], 8 | [ 9 | "./configure", 10 | "-bindir", 11 | "#{self.bin}", 12 | "-sitelib", 13 | "#{self.lib}", 14 | "-mandir", 15 | "#{self.man}", 16 | "-config", 17 | "#{self.lib}/findlib.conf", 18 | "-no-custom", 19 | "-no-topfind" 20 | ], 21 | [ 22 | "make", 23 | "all" 24 | ], 25 | [ 26 | "make", 27 | "opt" 28 | ] 29 | ], 30 | "install": [ 31 | [ 32 | "make", 33 | "install" 34 | ], 35 | [ 36 | "install", 37 | "-m", 38 | "0755", 39 | "ocaml-stub", 40 | "#{self.bin}/ocaml" 41 | ], 42 | [ 43 | "mkdir", 44 | "-p", 45 | "#{self.toplevel}" 46 | ], 47 | [ 48 | "install", 49 | "-m", 50 | "0644", 51 | "src/findlib/topfind", 52 | "#{self.toplevel}/topfind" 53 | ] 54 | ], 55 | "exportedEnv": { 56 | "OCAML_TOPLEVEL_PATH": { 57 | "val": "#{self.toplevel}", 58 | "scope": "global" 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__ocb_stubblr_opam__c__0.1.1_1_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@esy-ocaml/fauxpam": "0.1.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/esy.lock/overrides/opam__s__tsdl_opam__c__0.9.6_opam_override/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@esy-ocaml/fauxpam": "0.1.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactor-examples", 3 | "version": "0.0.0", 4 | "esy": { 5 | "build": "refmterr dune build -p #{self.name}", 6 | "NOTE": "" 7 | }, 8 | "dependencies": { 9 | "@esy-ocaml/reason": "*", 10 | "@opam/fmt": "*", 11 | "@opam/logs": "*", 12 | "@opam/tsdl": "0.9.6", 13 | "ocaml": "~4.7.0", 14 | "reactor": "*", 15 | "refmterr": "*" 16 | }, 17 | "resolutions": { 18 | "reactor": "github:ostera/reactor:reactor.opam#8b1bbbb" 19 | }, 20 | "devDependencies": { 21 | "@opam/dune": "*", 22 | "@opam/merlin": "*", 23 | "ocaml": "~4.7.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/sdl/Gui_test.re: -------------------------------------------------------------------------------- 1 | open Reactor.System; 2 | 3 | /** Logging setup */ 4 | Fmt_tty.setup_std_outputs(); 5 | Logs.set_level(Some(Logs.Error)); 6 | Logs.set_reporter(Logs_fmt.reporter()); 7 | 8 | /** System setup */ 9 | Reactor.Node.(Policy.default() |> setup); 10 | 11 | module Screen_cleaner = { 12 | open Tsdl; 13 | 14 | type color = (int, int, int); 15 | type state = { 16 | sdl_ctx: Reactor.Pid.t, 17 | color, 18 | }; 19 | 20 | let do_render = (sdl_ctx, (r, g, b)) => { 21 | let clear_screen = (_window, renderer) => { 22 | Sdl.set_render_draw_color(renderer, r, g, b, 255) |> ignore; 23 | Sdl.render_clear(renderer) |> ignore; 24 | Sdl.render_present(renderer) |> ignore; 25 | }; 26 | Sdl_ctx.M.run_pipeline(sdl_ctx, clear_screen); 27 | }; 28 | 29 | let next_color = (r, g, b) => { 30 | switch (r, g, b) { 31 | | (255, 255, 255) => (0, 0, 0) 32 | | (255, 255, _) => (r, g, b + 1) 33 | | (255, _, _) => (r, g + 1, b) 34 | | (_, _, _) => (r + 1, g, b) 35 | }; 36 | }; 37 | 38 | let loop: Reactor.Process.task(state) = 39 | (_ctx, state) => { 40 | do_render(state.sdl_ctx, state.color); 41 | let (r, g, b) = state.color; 42 | `Become({sdl_ctx: state.sdl_ctx, color: next_color(r, g, b)}); 43 | }; 44 | 45 | let start = (sdl_ctx, (r, g, b)) => { 46 | spawn(loop, {sdl_ctx, color: (r, g, b)}); 47 | }; 48 | }; 49 | 50 | let sdl_ctx = Sdl_ctx.start(); 51 | Sdl_ctx.M.init(sdl_ctx); 52 | let _ = Screen_cleaner.start(sdl_ctx, (0, 0, 0)); 53 | 54 | Reactor.Node.run(); 55 | -------------------------------------------------------------------------------- /examples/sdl/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name gui_test) 3 | (libraries reactor tsdl 4 | logs logs.fmt fmt fmt.tty)) 5 | -------------------------------------------------------------------------------- /examples/sdl/message_codec.re: -------------------------------------------------------------------------------- 1 | module type Base = {type t;}; 2 | 3 | /** Common message encoding/decoding */ 4 | module Make = (M: Base) => { 5 | let encode: M.t => string = x => Marshal.to_string(x, [Marshal.Closures]); 6 | let decode: string => M.t = x => Marshal.from_string(x, 0); 7 | }; 8 | -------------------------------------------------------------------------------- /examples/sdl/sdl_ctx.re: -------------------------------------------------------------------------------- 1 | /** SDL Context Process */ 2 | open Reactor.System; 3 | open Tsdl; 4 | 5 | type state = { 6 | window: option(Sdl.window), 7 | renderer: option(Sdl.renderer), 8 | }; 9 | 10 | module M = { 11 | type t = 12 | | Run_pipeline((Sdl.window, Sdl.renderer) => unit) 13 | | Init; 14 | 15 | include Message_codec.Make({ 16 | type nonrec t = t; 17 | }); 18 | 19 | let init: Reactor.Pid.t => unit = pid => pid <- (Init |> encode); 20 | 21 | let run_pipeline: (Reactor.Pid.t, (Sdl.window, Sdl.renderer) => unit) => unit = 22 | (pid, pipeline) => pid <- (Run_pipeline(pipeline) |> encode); 23 | }; 24 | 25 | let handle_message = (self, msg, state) => { 26 | switch (msg, state.window, state.renderer) { 27 | | (M.Init, None, _) => 28 | Logs.app(m => 29 | m("%s: Initializing SDL systems...", self |> Reactor.Pid.to_string) 30 | ); 31 | switch (Sdl.init(Sdl.Init.video)) { 32 | | Error(`Msg(e)) => 33 | Logs.err(m => m("[Sdl_ctx.handle_message] Init error: %s", e)); 34 | `Terminate; 35 | | Ok () => 36 | let window = 37 | Sdl.create_window(~w=640, ~h=480, "SDL OpenGL", Sdl.Window.opengl); 38 | switch (window) { 39 | | Error(`Msg(e)) => 40 | Logs.err(m => 41 | m("[Sdl_ctx.handle_message] Create window error: %s", e) 42 | ); 43 | `Terminate; 44 | | Ok(window) => 45 | switch (Sdl.create_renderer(window)) { 46 | | Error(`Msg(e)) => 47 | Logs.err(m => 48 | m("[Sdl_ctx.handle_message] Create window error: %s", e) 49 | ); 50 | `Terminate; 51 | | Ok(renderer) => 52 | Logs.app(m => 53 | m("%s: Initialization Complete!", self |> Reactor.Pid.to_string) 54 | ); 55 | 56 | `Become({window: Some(window), renderer: Some(renderer)}); 57 | } 58 | }; 59 | }; 60 | | (M.Run_pipeline(pipeline), Some(window), Some(renderer)) => 61 | pipeline(window, renderer); 62 | `Become(state); 63 | | _ => `Become(state) 64 | }; 65 | }; 66 | 67 | let handle_tick = state => { 68 | switch (state.window) { 69 | | Some(w) => 70 | let e = Sdl.Event.create(); 71 | let _ = Sdl.push_event(e); 72 | switch (Sdl.wait_event(Some(e))) { 73 | | Error(`Msg(err)) => 74 | Logs.err(m => m("[Sdl_ctx.handle_tick] Could not wait event: %s", err)); 75 | `Terminate; 76 | | Ok () => 77 | switch (Sdl.Event.(enum(get(e, typ)))) { 78 | | `Key_down 79 | | `Quit => 80 | Sdl.destroy_window(w); 81 | Sdl.quit(); 82 | `Terminate; 83 | | _ => `Become(state) 84 | } 85 | }; 86 | | _ => `Become(state) 87 | }; 88 | }; 89 | 90 | let loop: Reactor.Process.task(state) = 91 | (ctx, state) => 92 | switch (ctx.recv()) { 93 | | None => handle_tick(state) 94 | | Some(msg) => handle_message(ctx.self(), msg |> M.decode, state) 95 | }; 96 | 97 | let start = () => spawn(loop, {window: None, renderer: None}); 98 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactor", 3 | "version": "0.0.3", 4 | "keywords": [ "Actor-model", "actor", "concurrency" ], 5 | "author": "Leandro Ostera ", 6 | "license": "MIT", 7 | "esy": { "build": "refmterr dune build -p #{self.name}", "NOTE": "" }, 8 | "scripts": { 9 | "docs": "esy dune build @doc", 10 | "open-docs": "open #{self.target_dir}/default/_doc/_html/index.html" 11 | }, 12 | "dependencies": { 13 | "@esy-ocaml/reason": "*", 14 | "@opam/alcotest": "0.8.5", 15 | "@opam/benchmark": "1.6", 16 | "@opam/dune": "1.8.2", 17 | "@opam/fmt": "*", 18 | "@opam/logs": "*", 19 | "@opam/lwt": "*", 20 | "@opam/odoc": "1.4.0", 21 | "@opam/qcheck": "0.9", 22 | "@opam/qcheck-alcotest": "0.9", 23 | "ocaml": "~4.7.0", 24 | "refmterr": "*" 25 | }, 26 | "devDependencies": { 27 | "@opam/dune": "*", 28 | "@opam/merlin": "*", 29 | "ocaml": "~4.7.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /reactor.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | name: "reactor" 3 | version: "0.3" 4 | synopsis: "Actor-model Library" 5 | maintainer: "Leandro Ostera " 6 | authors: "Leandro Ostera " 7 | license: "MIT" 8 | homepage: "https//github.com/ostera/reactor" 9 | bug-reports: "https//github.com/ostera/reactor/issues" 10 | depends: [ 11 | "fmt" 12 | "logs" 13 | "lwt" 14 | 15 | "dune" {build} 16 | "reason" {build} 17 | ] 18 | build: ["dune" "build" "-p" name] 19 | install: ["dune" "install" name "--prefix" prefix "--root" "."] 20 | -------------------------------------------------------------------------------- /src/bytecode/bytecode.re: -------------------------------------------------------------------------------- 1 | type t = 2 | | Halt: t 3 | | Send_message(Process.Pid.t, Process.Message.t): t 4 | | Spawn(Process.Pid.t, Process.task('state), 'state): t; 5 | 6 | let to_string = 7 | fun 8 | | Halt => Printf.sprintf("Halt") 9 | | Send_message(pid, _) => 10 | Printf.sprintf("Send_message(%s)", pid |> Process.Pid.to_string) 11 | | Spawn(pid, _, _) => 12 | Printf.sprintf("Spawn(%s)", pid |> Process.Pid.to_string); 13 | -------------------------------------------------------------------------------- /src/bytecode/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name bytecode) 3 | (public_name reactor.bytecode) 4 | (libraries reactor.process)) 5 | -------------------------------------------------------------------------------- /src/coordinator/coordinator.re: -------------------------------------------------------------------------------- 1 | let create_pool = 2 | (~child_count, ~is_child, ~on_child, ~on_parent, ~after_child_spawn) => { 3 | Array.make(child_count, 0) 4 | |> Array.iteri((i, _) => 5 | switch (is_child()) { 6 | | false => 7 | Logs.info(m => 8 | m( 9 | "[%d] Spawning %d/%d ", 10 | Platform.Process.pid(), 11 | i + 1, 12 | child_count, 13 | ) 14 | ); 15 | let current = 16 | switch (Platform.Process.piped_fork()) { 17 | | `In_child(to_parent, from_parent) => 18 | on_child(Platform.Process.pid(), to_parent, from_parent); 19 | `From_child; 20 | | `In_parent(pid, write, read) => 21 | `From_parent(on_parent(pid, write, read)) 22 | }; 23 | switch (current) { 24 | | `From_parent(worker) => after_child_spawn(worker) 25 | | `From_child => () 26 | }; 27 | | _ => () 28 | } 29 | ); 30 | }; 31 | 32 | let read_task = Packet.read_from_pipe; 33 | let send_task = (task, fd) => 34 | Platform.Process.write(fd, ~buf=Packet.encode(task)); 35 | 36 | let wait_next_available = (read_fds, write_fds) => { 37 | let read_fds = List.map((`Read(fd)) => fd, read_fds); 38 | let write_fds = List.map((`Write(fd)) => fd, write_fds); 39 | 40 | let (reads, writes, _errors) = 41 | Platform.Process.select( 42 | ~read=read_fds, 43 | ~write=write_fds, 44 | ~except=[], 45 | ~timeout=-1.0, 46 | ); 47 | 48 | let receive = 49 | switch (reads) { 50 | | `Read(ins) when List.length(ins) > 0 => 51 | let cmds = 52 | List.fold_left( 53 | (acc, fd) => 54 | switch (Packet.read_from_pipe(`Read(fd))) { 55 | | None => acc 56 | | Some(data) => [data, ...acc] 57 | }, 58 | [], 59 | ins, 60 | ); 61 | `Receive(cmds); 62 | | _ => `Wait 63 | }; 64 | 65 | let sends = 66 | switch (writes) { 67 | | `Write(outs) when List.length(outs) > 0 => `Send(outs) 68 | | _ => `Wait 69 | }; 70 | 71 | (receive, sends); 72 | }; 73 | -------------------------------------------------------------------------------- /src/coordinator/coordinator.rei: -------------------------------------------------------------------------------- 1 | let create_pool: 2 | ( 3 | ~child_count: int, 4 | ~is_child: unit => bool, 5 | ~on_child: (int, Platform.Process.write_fd, Platform.Process.read_fd) => 6 | unit, 7 | ~on_parent: ( 8 | [> | `Child_pid(int)], 9 | Platform.Process.write_fd, 10 | Platform.Process.read_fd 11 | ) => 12 | 'a, 13 | ~after_child_spawn: 'a => unit 14 | ) => 15 | unit; 16 | 17 | let send_task: (Bytecode.t, Unix.file_descr) => unit; 18 | 19 | let wait_next_available: 20 | ( 21 | list([ | `Read(Unix.file_descr)]), 22 | list([ | `Write(Unix.file_descr)]) 23 | ) => 24 | ( 25 | [> | `Receive(list(Bytecode.t)) | `Wait], 26 | [> | `Send(list(Unix.file_descr)) | `Wait], 27 | ); 28 | 29 | let read_task: [< | `Read(Unix.file_descr)] => option(Bytecode.t); 30 | -------------------------------------------------------------------------------- /src/coordinator/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name coordinator) 3 | (public_name reactor.coordinator) 4 | (libraries reactor.platform reactor.bytecode)) 5 | -------------------------------------------------------------------------------- /src/coordinator/packet.re: -------------------------------------------------------------------------------- 1 | let header_size = 8; 2 | 3 | let encode = data => { 4 | let raw_data = Marshal.to_bytes(data, [Marshal.Closures]); 5 | let data_size = raw_data |> Bytes.length; 6 | let raw_size = data_size |> Int32.of_int |> Int32.to_string; 7 | let buf = Buffer.create(data_size + header_size); 8 | switch (header_size - (raw_size |> String.length)) { 9 | | 0 => () 10 | | n => Buffer.add_bytes(buf, Bytes.create(n) |> Bytes.map(_ => '0')) 11 | }; 12 | Buffer.add_string(buf, raw_size); 13 | Buffer.add_bytes(buf, raw_data); 14 | buf |> Buffer.to_bytes |> Bytes.to_string; 15 | }; 16 | 17 | let read_from_pipe = (`Read(pipe)) => { 18 | let raw_size = Platform.Process.read(pipe, ~len=header_size); 19 | switch (Int32.of_string_opt(raw_size)) { 20 | | None => None 21 | | Some(x) => 22 | let data_size = x |> Int32.to_int; 23 | let raw_data = Platform.Process.read(pipe, ~len=data_size); 24 | let value = Marshal.from_string(raw_data, 0); 25 | Some(value); 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /src/node/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name node) 3 | (public_name reactor.node) 4 | (libraries reactor.platform reactor.process reactor.scheduler reactor.task_queue)) 5 | -------------------------------------------------------------------------------- /src/node/node.re: -------------------------------------------------------------------------------- 1 | module Policy = Policy; 2 | 3 | type t = { 4 | unix_pid: int, 5 | should_halt: bool, 6 | policy: Policy.t, 7 | schedulers: Scheduler_view.Registry.t, 8 | tasks: Task_queue.t(Bytecode.t), 9 | }; 10 | 11 | let __is_node: ref(bool) = ref(true); 12 | 13 | let __node: ref(t) = 14 | ref({ 15 | unix_pid: Platform.Process.pid(), 16 | policy: Policy.default(), 17 | should_halt: false, 18 | schedulers: Scheduler_view.Registry.create(), 19 | tasks: Task_queue.create(), 20 | }); 21 | 22 | let current = () => __node^; 23 | 24 | let set_policy = policy => { 25 | __node := {...current(), policy}; 26 | }; 27 | 28 | let role = () => 29 | switch (Scheduler.current()) { 30 | | Some(s) => `Scheduler(s) 31 | | None => `Node(current()) 32 | }; 33 | 34 | let enqueue = (t, task) => Task_queue.queue(t.tasks, task); 35 | 36 | let halt = t => { 37 | Task_queue.clear(t.tasks); 38 | enqueue(t, Bytecode.Halt); 39 | }; 40 | 41 | let next_pid = (t, scheduler) => { 42 | let (scheduler', new_pid) = scheduler |> Scheduler_view.next_pid; 43 | let scheduler_id = scheduler' |> Scheduler_view.id |> Int32.of_int; 44 | Scheduler_view.Registry.update(t.schedulers, scheduler_id, scheduler'); 45 | new_pid; 46 | }; 47 | 48 | let least_busy_scheduler = t => t.schedulers |> Scheduler_view.least_busy; 49 | 50 | let setup = policy => { 51 | set_policy(policy); 52 | let {policy, schedulers, _} = current(); 53 | 54 | let mark_as_scheduler = () => { 55 | __is_node := false; 56 | }; 57 | 58 | let on_child = (pid, to_parent, from_parent) => { 59 | mark_as_scheduler(); 60 | Scheduler.setup(~pid, to_parent, from_parent) 61 | |> Scheduler.run(to_parent, from_parent); 62 | }; 63 | 64 | let on_parent = Scheduler_view.make; 65 | 66 | let after_child_spawn = scheduler => { 67 | let scheduler_id = scheduler |> Scheduler_view.id |> Int32.of_int; 68 | Scheduler_view.Registry.register(schedulers, scheduler_id, scheduler); 69 | }; 70 | 71 | Coordinator.create_pool( 72 | ~child_count=Policy.scheduler_count(policy), 73 | ~is_child=() => __is_node^ != true, 74 | ~on_child, 75 | ~on_parent, 76 | ~after_child_spawn, 77 | ); 78 | 79 | switch (role()) { 80 | | `Scheduler(_) => () 81 | | `Node(_) => 82 | Logs.info(m => { 83 | let pid = Platform.Process.pid(); 84 | let count = policy |> Policy.scheduler_count; 85 | let current_count = schedulers |> Scheduler_view.Registry.size; 86 | let ids = 87 | schedulers 88 | |> Scheduler_view.Registry.keys 89 | |> Seq.map(Int32.to_string) 90 | |> List.of_seq 91 | |> String.concat(", "); 92 | m("[%d] Spawned %d/%d schedulers: %s", pid, current_count, count, ids); 93 | }) 94 | }; 95 | }; 96 | 97 | let kill_schedulers = wrkrs => { 98 | let pids = wrkrs |> Seq.map(Scheduler_view.unix_pid) |> List.of_seq; 99 | pids |> List.iter(Platform.Process.kill); 100 | Logs.info(m => 101 | m( 102 | "[%d] Waiting for %d schedulers to finish...", 103 | Platform.Process.pid(), 104 | pids |> List.length, 105 | ) 106 | ); 107 | Platform.Process.wait(pids); 108 | }; 109 | 110 | let mark_system_to_halt_on_next_tick = () => { 111 | __node := {...__node^, should_halt: true}; 112 | }; 113 | 114 | let enter_loop = node => { 115 | let {schedulers, unix_pid, _} = node; 116 | Logs.info(m => m("[%d] Beginning node's coordinating loop...", unix_pid)); 117 | 118 | let (reads, writes) = 119 | schedulers 120 | |> Scheduler_view.Registry.values 121 | |> Seq.map(Scheduler_view.pipes) 122 | |> Seq.fold_left(Scheduler_view.fold_pipes, ([], [])); 123 | 124 | let rec do_loop = () => { 125 | let {tasks, should_halt, _} = current(); 126 | switch (should_halt) { 127 | | true => () 128 | | _ => 129 | let (reads, writes) = Coordinator.wait_next_available(reads, writes); 130 | 131 | switch (reads) { 132 | | `Receive(cmds) => List.iter(Task_queue.queue(tasks), cmds) 133 | | `Wait => () 134 | }; 135 | 136 | switch (writes) { 137 | | `Send(wrkr_fds) => 138 | let send_task = t => List.iter(Coordinator.send_task(t), wrkr_fds); 139 | switch (Task_queue.next(tasks)) { 140 | | None => () 141 | | Some(Bytecode.Halt as task) => 142 | mark_system_to_halt_on_next_tick(); 143 | send_task(task); 144 | | Some(task) => send_task(task) 145 | }; 146 | | `Wait => () 147 | }; 148 | 149 | do_loop(); 150 | }; 151 | }; 152 | 153 | do_loop(); 154 | }; 155 | 156 | let shutdown = node => { 157 | Logs.info(m => m("[%d] Node shutting down...", node.unix_pid)); 158 | __node := 159 | { 160 | ...node, 161 | should_halt: false, 162 | schedulers: Scheduler_view.Registry.create(), 163 | tasks: Task_queue.create(), 164 | }; 165 | kill_schedulers(node.schedulers |> Scheduler_view.Registry.values); 166 | Logs.info(m => m("[%d] Node shutdown completed.", node.unix_pid)); 167 | }; 168 | 169 | let run = () => { 170 | switch (role()) { 171 | | `Scheduler(scheduler) => 172 | let id = scheduler |> Scheduler.id; 173 | Logs.info(m => m("[%d] Scheduler shutting down...", id)); 174 | exit(0); 175 | | `Node(node) => 176 | enter_loop(node); 177 | shutdown(node); 178 | }; 179 | }; 180 | -------------------------------------------------------------------------------- /src/node/node.rei: -------------------------------------------------------------------------------- 1 | /** 2 | A node is a {i coordinator} of schedulers, with an identity of its own. 3 | */ 4 | type t; 5 | 6 | /** 7 | [role()] will check the current global state and determine if the current 8 | process is a [`Node] or a [`Scheduler]. 9 | */ 10 | let role: unit => [ | `Node(t) | `Scheduler(Scheduler.t)]; 11 | 12 | let run: unit => unit; 13 | 14 | let setup: Policy.t => unit; 15 | 16 | let enqueue: (t, Bytecode.t) => unit; 17 | 18 | let halt: t => unit; 19 | 20 | let least_busy_scheduler: t => option(Scheduler_view.t); 21 | 22 | let next_pid: (t, Scheduler_view.t) => Process.Pid.t; 23 | 24 | module Policy: (module type of Policy); 25 | -------------------------------------------------------------------------------- /src/node/policy.re: -------------------------------------------------------------------------------- 1 | type t = { 2 | /** The amount of schedulers to use */ 3 | schedulers: int, 4 | }; 5 | 6 | let default = () => {schedulers: Platform.cpu_count()}; 7 | 8 | let custom = (~scheduler_count) => {schedulers: scheduler_count}; 9 | 10 | let scheduler_count = t => t.schedulers; 11 | -------------------------------------------------------------------------------- /src/node/policy.rei: -------------------------------------------------------------------------------- 1 | /** 2 | The type of a Policy. 3 | */ 4 | type t; 5 | 6 | /** 7 | The default policy used with the scheduler. Will use as many schedulers as CPU 8 | cores available. 9 | */ 10 | let default: unit => t; 11 | 12 | /** 13 | Custom policy where all options are configurable. 14 | */ 15 | let custom: (~scheduler_count: int) => t; 16 | 17 | /** 18 | The amount of schedulers the policy expects to run. 19 | */ 20 | let scheduler_count: t => int; 21 | -------------------------------------------------------------------------------- /src/node/scheduler_view.re: -------------------------------------------------------------------------------- 1 | type t = { 2 | id: int, 3 | unix_pid: int, 4 | pipe_to_scheduler: Unix.file_descr, 5 | pipe_from_scheduler: Unix.file_descr, 6 | last_pid: Process.Pid.t, 7 | process_count: int, 8 | }; 9 | 10 | let make = (`Child_pid(pid), `Write(to_scheduler), `Read(from_scheduler)) => { 11 | id: pid, 12 | unix_pid: pid, 13 | pipe_to_scheduler: to_scheduler, 14 | pipe_from_scheduler: from_scheduler, 15 | last_pid: Process.Pid.make(0, pid, 0), 16 | process_count: 0, 17 | }; 18 | 19 | let id = t => t.id; 20 | 21 | let unix_pid = t => t.unix_pid; 22 | 23 | let last_pid = t => t.last_pid; 24 | 25 | let next_pid = scheduler => { 26 | let pid = scheduler.last_pid |> Process.Pid.next; 27 | ( 28 | {...scheduler, last_pid: pid, process_count: scheduler.process_count + 1}, 29 | pid, 30 | ); 31 | }; 32 | 33 | module Registry: Registry.REGISTRY with type key = Int32.t and type value = t = 34 | Registry.Make({ 35 | type key = Int32.t; 36 | let equal = Int32.equal; 37 | let hash = Hashtbl.hash; 38 | type value = t; 39 | }); 40 | 41 | let pipes = t => ( 42 | `Read(t.pipe_from_scheduler), 43 | `Write(t.pipe_to_scheduler), 44 | ); 45 | 46 | let fold_pipes = ((reads, writes), (read, write)) => { 47 | ([read, ...reads], [write, ...writes]); 48 | }; 49 | 50 | let least_busy = schedulers => { 51 | let by_process_count = (w1, w2) => w1.process_count - w2.process_count; 52 | let sorted = 53 | schedulers 54 | |> Registry.values 55 | |> List.of_seq 56 | |> List.sort(by_process_count); 57 | switch (sorted) { 58 | | [hd, ..._] => Some(hd) 59 | | _ => None 60 | }; 61 | }; 62 | -------------------------------------------------------------------------------- /src/platform/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name platform) 3 | (public_name reactor.platform) 4 | (libraries unix logs)) 5 | -------------------------------------------------------------------------------- /src/platform/platform.re: -------------------------------------------------------------------------------- 1 | module Process = Process; 2 | 3 | let cpu_count = () => 4 | try ( 5 | switch (Sys.os_type) { 6 | | "Win32" => Sys.getenv("NUMBER_OF_PROCESSORS") |> int_of_string 7 | | _ => 8 | let ic = Unix.open_process_in("getconf _NPROCESSORS_ONLN"); 9 | ic |> input_line |> int_of_string; 10 | } 11 | ) { 12 | | _ => 1 13 | }; 14 | -------------------------------------------------------------------------------- /src/platform/platform.rei: -------------------------------------------------------------------------------- 1 | /** 2 | Abstraction layer on top of the current platform for a little more 3 | type-safety on communicating processes. 4 | */ 5 | module Process: { 6 | type read_fd = [ | `Read(Unix.file_descr)]; 7 | 8 | type write_fd = [ | `Write(Unix.file_descr)]; 9 | 10 | /** 11 | [pid()] evaluates to the current operating-system process identifier number. 12 | */ 13 | let pid: unit => int; 14 | 15 | /** 16 | [kill(n)] 17 | */ 18 | let kill: int => unit; 19 | 20 | /** 21 | [wait(ps)] will block until all [ps] pids are terminated. 22 | */ 23 | let wait: list(int) => unit; 24 | 25 | /** 26 | [write(fd, ~buf=bytes)] will write [bytes] into [fd]. 27 | */ 28 | let write: (Unix.file_descr, ~buf: string) => unit; 29 | 30 | /** 31 | [read(fd, ~len=n)] will read [n] bytes out of [fd] into a string. 32 | */ 33 | let read: (Unix.file_descr, ~len: int) => string; 34 | 35 | let pipe: unit => (read_fd, write_fd); 36 | 37 | let piped_fork: 38 | unit => 39 | [> 40 | | `In_child(write_fd, read_fd) 41 | | `In_parent([> | `Child_pid(int)], write_fd, read_fd) 42 | ]; 43 | 44 | let select: 45 | ( 46 | ~read: list(Unix.file_descr), 47 | ~write: list(Unix.file_descr), 48 | ~except: list(Unix.file_descr), 49 | ~timeout: float 50 | ) => 51 | ( 52 | [> | `Read(list(Unix.file_descr))], 53 | [> | `Write(list(Unix.file_descr))], 54 | [> | `Except(list(Unix.file_descr))], 55 | ); 56 | }; 57 | 58 | /** [cpu_count()] evaluates to the current CPU count. */ 59 | let cpu_count: unit => int; 60 | -------------------------------------------------------------------------------- /src/platform/process.re: -------------------------------------------------------------------------------- 1 | module Unix = UnixLabels; 2 | 3 | type read_fd = [ | `Read(Unix.file_descr)]; 4 | 5 | type write_fd = [ | `Write(Unix.file_descr)]; 6 | 7 | let pipe = () => { 8 | let (r, w) = Unix.pipe(); 9 | (`Read(r), `Write(w)); 10 | }; 11 | 12 | let write = (fd, ~buf) => { 13 | let buf = buf |> Bytes.of_string; 14 | let len = buf |> Bytes.length; 15 | let _ = Unix.write(fd, ~buf, ~pos=0, ~len); 16 | (); 17 | }; 18 | 19 | let read = (fd, ~len) => { 20 | let buf = Bytes.create(len); 21 | let rec read_pipe = (pos, len) => { 22 | switch (Unix.read(fd, ~buf, ~pos, ~len)) { 23 | | exception _ => buf 24 | | 0 => buf 25 | | n => 26 | switch (n + (buf |> Bytes.length) >= len) { 27 | | true => buf 28 | | _ => read_pipe(pos + n, len - n) 29 | } 30 | }; 31 | }; 32 | read_pipe(0, len) |> Bytes.to_string; 33 | }; 34 | 35 | let fork = () => { 36 | switch (Unix.fork()) { 37 | | 0 => `In_child 38 | | pid => `In_parent(pid) 39 | }; 40 | }; 41 | 42 | let pid = Unix.getpid; 43 | 44 | let piped_fork = () => { 45 | let (`Read(read_child), `Write(write_child)) = pipe(); 46 | let (`Read(read_parent), `Write(write_parent)) = pipe(); 47 | 48 | switch (fork()) { 49 | | `In_child => 50 | Unix.close(write_parent); 51 | Unix.close(read_child); 52 | `In_child((`Write(write_child), `Read(read_parent))); 53 | | `In_parent(pid) => 54 | Unix.close(read_parent); 55 | Unix.close(write_child); 56 | `In_parent((`Child_pid(pid), `Write(write_parent), `Read(read_child))); 57 | }; 58 | }; 59 | 60 | let select = (~read, ~write, ~except, ~timeout) => { 61 | switch (Unix.select(~read, ~write, ~except, ~timeout)) { 62 | | (read, write, except) => (`Read(read), `Write(write), `Except(except)) 63 | }; 64 | }; 65 | 66 | let kill = pid => Unix.kill(~pid, ~signal=Sys.sigkill); 67 | 68 | let rec wait = xs => 69 | switch (xs) { 70 | | [_, ...ps] => 71 | Unix.wait() |> ignore; 72 | wait(ps); 73 | | [] => () 74 | }; 75 | -------------------------------------------------------------------------------- /src/process/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name process) 3 | (public_name reactor.process) 4 | (libraries reactor.registry fmt logs lwt)) 5 | -------------------------------------------------------------------------------- /src/process/index.mld: -------------------------------------------------------------------------------- 1 | {0:top 🚀 re:actor — Bringing Typesafe Message-passing Concurrency to the Web} 2 | 3 | [re:actor] is an {e experimental} type-safe, message-passing concurrency 4 | library. It is not meant for production and has no stable API. 5 | 6 | For the top-level library module see {!ReActor}. 7 | 8 | {%html: 9 | 10 | %} 11 | 12 | {%html: 13 | 43 | %} 44 | 45 | {1:introduction 1. Introduction} 46 | 47 | Web applications today run by default in a single-threaded event loop that does 48 | not effectively leverage the many-core architectures available. This means that 49 | in a many-core computer, where a web application could be potentially executing 50 | many parallel actions at once, it typically executes only one. 51 | 52 | The appearance of Web Workers changed this by allowing arbitrary Javascript 53 | code to be executed in a separate event-loop that can communicate with the main 54 | event loop via message passing and transferable data structures. To this day it 55 | still is not trivial to leverage them: given they are very coarse low-level 56 | features, any higher-level concurrency feature is left to be implemented at the 57 | application level. 58 | 59 | To aggravate this issue, a failure or resource-starvation in the main program 60 | of a worker will effectively take the worker out of service. 61 | 62 | To address these issues, [re:actor] began as an experiment for type-safe, 63 | message-passing concurrent computation modeled after Smalltalk-72, Erlang, and 64 | Gul Agha's Actor model. 65 | 66 | This experiment will be evaluated based on how well it provides: 67 | 68 | - Multi-core Support: or how seamlessly it allows an application to leverage 69 | parallelism in many-core computers. 70 | 71 | - Failure Isolation: a process failure should not have an implicit impact on 72 | the rest of the system. 73 | 74 | - Type-safe Message Passing: processes can be checked to handle all of the 75 | messages they expect to handle at compile time. 76 | 77 | These evaluation will be carried out by writing a number of small projects that 78 | showcase these capabilities. 79 | 80 | {1:overview 2. Overview} 81 | 82 | [re:actor] is designed to allow web applications to be expressed as a group of 83 | independent processes that communicate by sending messages to each other, 84 | leveraging the entirety of their host's available computing power 85 | seamlessly. 86 | 87 | {%html: 88 | 93 | %} 94 | 95 | {2 2.1 Basics} 96 | 97 | Let us start by introducing the basic constructs the library builds upon. 98 | 99 | {b Processes} applications built with [re:actor] consist of running processes. 100 | These processes model {i tasks} that have to be carried out and {i entities} 101 | that evolve over time, in the form of {i functions} with associated identities 102 | and mailboxes. These processes can be as simple as incrementing a counter, or 103 | as complex as coordinating transactions across other processes. They collaborate 104 | by {i message-passing}. In practice, processes can blend completely into the 105 | domain of the application, making them an incredibly versatile abstraction to 106 | model systems with. 107 | 108 | {b Messages} Messages are typed data structures that processes send to each 109 | other to communicate. 110 | 111 | {b Schedulers} All processes must be scheduled for execution, and to do this 112 | there exist schedulers. Processes and their mailboxes live within particular 113 | schedulers. A scheduler corresponds to a single event-loop, and this could be 114 | either the Main Thread of a browser, or a Web Worker. Every time a process send 115 | a message, it is a scheduler that will make sure it gets delivered. 116 | 117 | {b Nodes} All schedulers within a running system have to be orchestrated by a 118 | node. Nodes typically map 1-to-1 with a single computer. If you're running a 119 | [re:actor] application in a single browser, you'd normally run a single node. A 120 | node will make sure there are as many schedulers as machine cores available and 121 | that they are healthy at all points. 122 | {%html: 123 | 128 | %} 129 | 130 | {2 2.2 Processes and Behaviors} 131 | 132 | A Process is in essence a function with an associated identity and a mailbox. 133 | 134 | {[ 135 | type process = ( func, pid, mailbox ); 136 | ]} 137 | 138 | Every process has a unique identifier, it's {i pid}, that can be used to locate 139 | the process and send messages to it's mailbox from anywhere in the node. 140 | 141 | The function that defines the process is a function from a particular initial 142 | state to a behavior change. There is a limited number of behaviors that encode 143 | termination of a process' execution, continuation, and suspension. Additionally, 144 | a particular mode of suspension catered for performing drawing on the Web is 145 | included: suspension until the next animation frame. 146 | 147 | {[ 148 | type behavior('s) = 149 | | Become('s) 150 | | OnAnimationFrame('s) 151 | | Suspend(int, 's) 152 | | Terminate; 153 | ]} 154 | 155 | Every process definition function will take an initial state and return one of 156 | the above behaviors, making it possible to re-schedule itself by {i becoming} a 157 | process with the same identity, the same definition function, and a new initial 158 | state. 159 | 160 | {2 2.3 Guaranteed Message-passing} 161 | 162 | Processes communicate with other processes via {i message passing}, where a 163 | message gets copied from the sending process to the receiving process' mailbox. 164 | 165 | Message passing in [re:actor] is {i guaranteed to deliver messages}. However, 166 | because the behavior of a process consists of application code that might never 167 | consume messages from it's mailbox, it is impossible to guarantee that messages 168 | will be consumed. 169 | 170 | {%html: 171 | 176 | %} 177 | 178 | To guarantee message passing, the [send] function available to all processes 179 | within a node is {i synchronous} and will fail if the message could not be 180 | effectively copied to the receiving mailbox. 181 | 182 | {2 2.4 Typesafe Message-passing} 183 | 184 | To provide further safety, a process must define exactly what messages to accept 185 | when consuming it's mailbox, and should only be able to handle such messages. 186 | 187 | This particular capability is powered by the type-system underneath Reason. 188 | 189 | {2 2.5 Seamless Multi-core} 190 | 191 | By making processes {i relocatable}, they can be started in any of the available 192 | schedulers. 193 | 194 | {2 2.6 Fair Scheduling} 195 | 196 | Languages like Erlang or Smalltalk have mechanisms for principled preemptive 197 | scheduling, in which the execution of a particular process will be suspended 198 | without any loss of state, allowing other processes to be executed. 199 | 200 | However, the Web platform and in particular Javascript, have no such mechanisms. 201 | 202 | In Javascript, any function that includes an infinite loop will yield a process 203 | that never terminates, and any function making use of recursion may cause a 204 | stack-overflow that will crash a process. 205 | 206 | Because of this impediments, the scheduling of [re:actor] is designed to entrust 207 | to the user the responsibility of building processes out of {i total functions} 208 | that terminate in {i negligible amounts of time}. Naturally, this isn't always 209 | possible, and when it isn't, the tradeoff has to be made clear: 210 | 211 | If a process' function definition is {i partial} or executes a time-intense 212 | computation, it will block the scheduler until it terminates. 213 | 214 | As a rule of thumb, keeping processes focused will yield better overall 215 | performance. If you see a process growing in complexity, consider refactoring it 216 | into a family of processes that either sequence the work or can perform it in 217 | parallel. 218 | 219 | {1:experiments 3. Experiments} 220 | 221 | The experiments below (up to number 7th) started off as {i Koans} for the 222 | library. They serve as good examples of how to use the library, increasing in 223 | complexity, and to describe additional features that were found necessary to 224 | build web applications. 225 | 226 | {2 3.1 Simple Spawning} 227 | 228 | {{:https://github.com/ostera/reactor/blob/master/examples/koans/E1_SimpleSpawning.re} 229 | View Source} — {{:/reactor/examples/koans/E1_SimpleSpawning.re.html} Run experiment (make sure to have the console open)}. 230 | 231 | Let us begin with a simple process: a monotonically incremental counter. 232 | 233 | {[ 234 | /** 235 | Sample state that includes a simple integer counter. 236 | */ 237 | type sample = {n: int}; 238 | 239 | /** 240 | A counter process that will increment it's counter by one on each evaluation. 241 | */ 242 | let counter: Process.f(sample) = (_env, state) => Become({n: state.n + 1}); 243 | ]} 244 | 245 | This process definition is amongst the simplest possible ones. It defines a 246 | process that will simply become itself with a new initial state, where the 247 | counter value [n] is incremented by 1 in every step. 248 | 249 | {%html: 250 | 255 | %} 256 | 257 | How fast will this particular counter increment itself? As fast as it gets 258 | scheduled for execution. 259 | 260 | We can schedule this process for execution like this: 261 | 262 | {[ 263 | let counter_pid: Pid.t = spawn(counter, {n: 0}); 264 | ]} 265 | 266 | But this isn't very useful, since we can't make use of that internal value 267 | without recurring to mutable shared state with [refs]. We avoid communicating by 268 | sharing memory and instead we share memory by communicating. 269 | 270 | Let's instead add another process definition that will show us this data in some 271 | form so we verify it is indeed working: 272 | 273 | {[ 274 | /** 275 | A counter process that will increment it's counter by one on each evaluation 276 | and will log out a message when the counter reaches a certain number. 277 | */ 278 | let printing_counter: int => Process.f(sample) = (number, _env, state) => { 279 | if (state.n == number) { 280 | Js.log({j|Reached number $number|j}); 281 | }; 282 | Become({n: state.n + 1}); 283 | }; 284 | ]} 285 | 286 | Now spawning one process with behavior [printing_counter(2112)] will eventually 287 | print out {i "Reached number 2112"}. A small problem appears when we have 288 | multiple processes running in this way: 289 | 290 | {[ 291 | let p1 = spawn(printing_counter(2112), {n: 0}); 292 | let p2 = spawn(printing_counter(2112), {n: 0}); 293 | let p3 = spawn(printing_counter(2112), {n: 0}); 294 | 295 | /* eventually... */ 296 | < Reached number 2112 297 | < Reached number 2112 298 | < Reached number 2112 299 | ]} 300 | 301 | What printing belongs to which process? We can find out information about 302 | the current process by accessing the {i process environment}: {! 303 | ReActor_Process.env}. It is available as the [_env] parameter that we see in 304 | both definitions above. We can use the function {! ReActor_Process.env.self} to 305 | get the current process identifier, and refactor to print it out: 306 | 307 | {[ 308 | let printing_counter: int => Process.f(sample) = (number, env, state) => { 309 | if (state.n == number) { 310 | let pid = env.self() |> Pid.toString; 311 | Js.log({j|$pid :: Reached number $number|j}); 312 | }; 313 | Become({n: state.n + 1}); 314 | }; 315 | ]} 316 | 317 | And now running it prints out the identifier of the process on each line: 318 | 319 | {[ 320 | <0,0,1> :: Reached number 2112 321 | <0,0,3> :: Reached number 2112 322 | <0,0,2> :: Reached number 2112 323 | ]} 324 | 325 | {%html: 326 | 331 | %} 332 | 333 | {2 3.2 Simple Message Passing} 334 | {{:https://github.com/ostera/reactor/blob/master/examples/koans/E2_SimpleMessagePassing.re} 335 | View Source} — {{:/reactor/examples/koans/E2_SimpleMessagePassing.re.html} Run experiment (make sure to have the console open)}. 336 | 337 | {2 3.3 Collaborating Processes} 338 | {{:https://github.com/ostera/reactor/blob/master/examples/koans/E3_CollaboratingProcesses.re} 339 | View Source} — {{:/reactor/examples/koans/E3_CollaboratingProcesses.re.html} Run experiment (make sure to have the console open)}. 340 | 341 | {2 3.4 More Collaborating Processes} 342 | {{:https://github.com/ostera/reactor/blob/master/examples/koans/E4_MoreCollaboratingProcesses.re} 343 | View Source} — {{:/reactor/examples/koans/E4_MoreCollaboratingProcesses.re.html} Run experiment (make sure to have the console open)}. 344 | 345 | {2 3.5 Processes for the DOM} 346 | {{:https://github.com/ostera/reactor/blob/master/examples/koans/E5_ProcessesForTheDOM.re} 347 | View Source} — {{:/reactor/examples/koans/E5_ProcessesForTheDOM.re.html} Run experiment (make sure to have the console open)}. 348 | 349 | {2 3.6 Processes with React} 350 | {{:https://github.com/ostera/reactor/blob/master/examples/koans/E6_ProcessesWithReact.re} 351 | View Source} — {{:/reactor/examples/koans/E6_ProcessesWithReact.re.html} Run experiment (make sure to have the console open)}. 352 | 353 | {2 3.7 Tracing Messages } 354 | {{:https://github.com/ostera/reactor/blob/master/examples/koans/E7_TracingMessages.re} 355 | View Source} — {{:/reactor/examples/koans/E7_TracingMessages.re.html} Run experiment (make sure to have the console open)}. 356 | 357 | {2 3.8 Processes Orchestrating Processes} 358 | {{:https://github.com/ostera/reactor/blob/master/examples/koans/E8_ProcesssesOrchestratingProcesses.re} 359 | View Source} — {{:/reactor/examples/koans/E8_ProcesssesOrchestratingProcesses.re.html} Run experiment (make sure to have the console open)}. 360 | 361 | 362 | {1:benchmarks 4. Benchmarks} 363 | 364 | {1:conclusion 5. Conclusion} 365 | 366 | {1:references 6. References} 367 | 368 | - {{:https://en.wikipedia.org/wiki/Smalltalk}Smalltalk} 369 | - {{:http://www.erlang.org/}Erlang} and {{:https://elixir-lang.org/}Elixir} 370 | - {{:https://arxiv.org/vc/arxiv/papers/1008/1008.1459v8.pdf}Hewitt's Actor Model 371 | of Computation} 372 | - {{:https://mitpress.mit.edu/books/actors}Gul Agha's Actors} 373 | - {{:https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API} Web 374 | Workers } 375 | - {{:http://www-inst.eecs.berkeley.edu/~n252/paper/Amdahl.pdf} Amdahl's Law} 376 | -------------------------------------------------------------------------------- /src/process/mailbox.re: -------------------------------------------------------------------------------- 1 | type t = Queue.t(Message.t); 2 | 3 | let send = (mailbox, msg) => { 4 | Queue.push(msg, mailbox); 5 | }; 6 | 7 | let recv = mailbox => { 8 | switch (Queue.pop(mailbox)) { 9 | | exception Queue.Empty => None 10 | | msg => Some(msg) 11 | }; 12 | }; 13 | 14 | let create = Queue.create; 15 | -------------------------------------------------------------------------------- /src/process/mailbox.rei: -------------------------------------------------------------------------------- 1 | type t; 2 | 3 | let send: (t, Message.t) => unit; 4 | 5 | let recv: t => option(Message.t); 6 | 7 | let create: unit => t; 8 | -------------------------------------------------------------------------------- /src/process/message.re: -------------------------------------------------------------------------------- 1 | type t = string; 2 | -------------------------------------------------------------------------------- /src/process/message.rei: -------------------------------------------------------------------------------- 1 | type t = string; 2 | -------------------------------------------------------------------------------- /src/process/pid.re: -------------------------------------------------------------------------------- 1 | type t = (int, int, int); 2 | 3 | type view = { 4 | node_id: int32, 5 | scheduler_id: int32, 6 | process_id: int32, 7 | }; 8 | 9 | let make = (node, scheduler, process) => (node, scheduler, process); 10 | 11 | let view = ((n, s, p)) => { 12 | node_id: n |> Int32.of_int, 13 | scheduler_id: s |> Int32.of_int, 14 | process_id: p |> Int32.of_int, 15 | }; 16 | 17 | let to_string = ((n, s, p)) => Printf.sprintf("<%d,%d,%d>", n, s, p); 18 | 19 | let equal = ((n1, s1, p1), (n2, s2, p2)) => 20 | n1 == n2 && s1 == s2 && p1 == p2; 21 | 22 | let next = ((n, s, p)) => (n, s, p + 1); 23 | 24 | /* TODO(@ostera): Replace! */ 25 | let hash = Hashtbl.hash; 26 | -------------------------------------------------------------------------------- /src/process/process.re: -------------------------------------------------------------------------------- 1 | module Pid = Pid; 2 | module Message = Message; 3 | 4 | type behavior('s) = [ | `Become('s) | `Terminate | `Defer(Lwt.t('s))]; 5 | 6 | type env('s) = { 7 | self: unit => Pid.t, 8 | recv: unit => option(string), 9 | }; 10 | 11 | type task('s) = (env('s), 's) => behavior('s); 12 | 13 | type t = { 14 | pid: Pid.t, 15 | mailbox: Mailbox.t, 16 | }; 17 | 18 | let send = (proc, msg) => Mailbox.send(proc.mailbox, msg); 19 | 20 | let recv = (proc, ()) => Mailbox.recv(proc.mailbox); 21 | 22 | let make = pid => {pid, mailbox: Mailbox.create()}; 23 | 24 | module Registry: Registry.REGISTRY with type key = Pid.t and type value = t = 25 | Registry.Make({ 26 | type key = Pid.t; 27 | type value = t; 28 | let equal = Pid.equal; 29 | let hash = Pid.hash; 30 | }); 31 | -------------------------------------------------------------------------------- /src/process/process.rei: -------------------------------------------------------------------------------- 1 | module Message: {type t = string;}; 2 | 3 | module Pid: { 4 | type t; 5 | 6 | type view = { 7 | node_id: int32, 8 | scheduler_id: int32, 9 | process_id: int32, 10 | }; 11 | 12 | let make: (int, int, int) => t; 13 | 14 | let view: t => view; 15 | 16 | let to_string: t => string; 17 | 18 | let equal: (t, t) => bool; 19 | 20 | let next: t => t; 21 | 22 | let hash: t => int; 23 | }; 24 | 25 | type behavior('s) = [ | `Become('s) | `Terminate | `Defer(Lwt.t('s))]; 26 | 27 | type env('s) = { 28 | self: unit => Pid.t, 29 | recv: unit => option(string), 30 | }; 31 | 32 | type task('s) = (env('s), 's) => behavior('s); 33 | 34 | type t; 35 | 36 | let send: (t, Message.t) => unit; 37 | 38 | let recv: (t, unit) => option(string); 39 | 40 | let make: Pid.t => t; 41 | 42 | module Registry: Registry.REGISTRY with type key = Pid.t and type value = t; 43 | -------------------------------------------------------------------------------- /src/reactor/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name reactor) 3 | (public_name reactor) 4 | (libraries 5 | reactor.tasks reactor.node reactor.process 6 | logs logs.fmt fmt fmt.tty)) 7 | -------------------------------------------------------------------------------- /src/reactor/reactor.re: -------------------------------------------------------------------------------- 1 | module Node = Node; 2 | module Process = Process; 3 | module Pid = Process.Pid; 4 | 5 | module System = { 6 | include Tasks; 7 | }; 8 | -------------------------------------------------------------------------------- /src/registry/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name registry) 3 | (public_name reactor.registry)) 4 | -------------------------------------------------------------------------------- /src/registry/registry.re: -------------------------------------------------------------------------------- 1 | module type Base = { 2 | type key; 3 | 4 | let equal: (key, key) => bool; 5 | 6 | let hash: key => int; 7 | 8 | type value; 9 | }; 10 | 11 | module type REGISTRY = { 12 | type key; 13 | 14 | type value; 15 | 16 | type t; 17 | 18 | let create: (~size: int=?, unit) => t; 19 | 20 | let find: (t, key) => option(value); 21 | 22 | let register: (t, key, value) => unit; 23 | 24 | let unregister: (t, key) => unit; 25 | 26 | let update: (t, key, value) => unit; 27 | 28 | let size: t => int; 29 | 30 | let keys: t => Seq.t(key); 31 | 32 | let values: t => Seq.t(value); 33 | }; 34 | 35 | module Make = 36 | (M: Base) 37 | : (REGISTRY with type key = M.key and type value = M.value) => { 38 | module Table = 39 | Hashtbl.Make({ 40 | type t = M.key; 41 | let equal = M.equal; 42 | let hash = M.hash; 43 | }); 44 | 45 | type key = M.key; 46 | 47 | type value = M.value; 48 | 49 | type t = Table.t(M.value); 50 | 51 | let create = (~size=1024, ()) => Table.create(size); 52 | 53 | let find = Table.find_opt; 54 | 55 | let register = Table.add; 56 | 57 | let unregister = Table.remove; 58 | 59 | let update = (r, key, value) => { 60 | unregister(r, key); 61 | register(r, key, value); 62 | }; 63 | 64 | let size = Table.length; 65 | 66 | let keys = Table.to_seq_keys; 67 | 68 | let values = Table.to_seq_values; 69 | }; 70 | -------------------------------------------------------------------------------- /src/registry/registry.rei: -------------------------------------------------------------------------------- 1 | module type Base = { 2 | type key; 3 | 4 | let equal: (key, key) => bool; 5 | 6 | let hash: key => int; 7 | 8 | type value; 9 | }; 10 | 11 | module type REGISTRY = { 12 | type key; 13 | 14 | type value; 15 | 16 | type t; 17 | 18 | let create: (~size: int=?, unit) => t; 19 | 20 | let find: (t, key) => option(value); 21 | 22 | let register: (t, key, value) => unit; 23 | 24 | let unregister: (t, key) => unit; 25 | 26 | let update: (t, key, value) => unit; 27 | 28 | let size: t => int; 29 | 30 | let keys: t => Seq.t(key); 31 | 32 | let values: t => Seq.t(value); 33 | }; 34 | 35 | module Make: 36 | (M: Base) => REGISTRY with type key = M.key and type value = M.value; 37 | -------------------------------------------------------------------------------- /src/scheduler/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name scheduler) 3 | (public_name reactor.scheduler) 4 | (libraries reactor.coordinator reactor.task_queue reactor.process reactor.bytecode platform logs unix lwt lwt.unix)) 5 | -------------------------------------------------------------------------------- /src/scheduler/scheduler.re: -------------------------------------------------------------------------------- 1 | type task = [ 2 | | `From_coordinator(Bytecode.t) 3 | | `From_scheduler(Bytecode.t) 4 | | `Reduction(unit => unit) 5 | ]; 6 | 7 | type t = { 8 | id: int, 9 | unix_pid: int, 10 | pipe_to_coordinator: Unix.file_descr, 11 | pipe_from_coordinator: Unix.file_descr, 12 | should_halt: ref(bool), 13 | last_pid: ref(Process.Pid.t), 14 | processes: Process.Registry.t, 15 | process_count: int, 16 | tasks: Task_queue.t(task), 17 | }; 18 | 19 | let __scheduler: ref(option(t)) = ref(None); 20 | 21 | let current = () => __scheduler^; 22 | 23 | let is_scheduler = () => 24 | switch (current()) { 25 | | None => false 26 | | _ => true 27 | }; 28 | 29 | let id = t => t.id; 30 | 31 | let next_pid = t => { 32 | let pid = Process.Pid.next(t.last_pid^); 33 | t.last_pid := pid; 34 | pid; 35 | }; 36 | 37 | let last_pid = t => t.last_pid^; 38 | 39 | let enqueue = (t, task) => Task_queue.queue(t.tasks, task); 40 | 41 | let halt = t => { 42 | Task_queue.clear(t.tasks); 43 | enqueue(t, `From_scheduler(Bytecode.Halt)); 44 | }; 45 | 46 | let setup = (~pid, `Write(to_parent), `Read(from_parent)) => { 47 | Logs.info(m => m("[%d] Setting up scheduler...", pid)); 48 | let scheduler = { 49 | id: pid, 50 | unix_pid: pid, 51 | pipe_to_coordinator: to_parent, 52 | pipe_from_coordinator: from_parent, 53 | should_halt: ref(false), 54 | last_pid: ref(Process.Pid.make(0, pid, 0)), 55 | processes: Process.Registry.create(), 56 | process_count: 0, 57 | tasks: Task_queue.create(), 58 | }; 59 | __scheduler := Some(scheduler); 60 | scheduler; 61 | }; 62 | 63 | let handle_spawn = (scheduler, pid, task, state) => { 64 | let proc = Process.make(pid); 65 | let env = Process.{self: () => pid, recv: Process.recv(proc)}; 66 | 67 | Process.Registry.register(scheduler.processes, pid, proc); 68 | 69 | let queue_reduction = f => { 70 | let reduction = `Reduction(f); 71 | Task_queue.queue(scheduler.tasks, reduction); 72 | }; 73 | 74 | let terminate = () => Process.Registry.unregister(scheduler.processes, pid); 75 | 76 | let rec run_process = args => { 77 | switch (task(env, args)) { 78 | | exception ex => 79 | Logs.debug(m => 80 | m( 81 | "Process Terminated: %s threw %s", 82 | pid |> Process.Pid.to_string, 83 | ex |> Printexc.to_string, 84 | ) 85 | ) 86 | | `Terminate => terminate() 87 | | `Become(next_state) => queue_reduction(() => run_process(next_state)) 88 | | `Defer(next_state_promise) => 89 | queue_reduction(() => { 90 | Lwt.on_success(next_state_promise, next_state => 91 | queue_reduction(() => run_process(next_state)) 92 | ); 93 | Lwt.on_failure(next_state_promise, _ => terminate()); 94 | }) 95 | }; 96 | }; 97 | run_process(state); 98 | }; 99 | 100 | let handle_send_message = (scheduler, pid, msg) => { 101 | switch (Process.Registry.find(scheduler.processes, pid)) { 102 | | None => () 103 | | Some(proc) => Process.send(proc, msg) 104 | }; 105 | }; 106 | 107 | let handle_halt = scheduler => { 108 | scheduler.should_halt := true; 109 | }; 110 | 111 | let should_handle_task_locally = (scheduler, task) => { 112 | switch (task) { 113 | | Bytecode.Halt => false 114 | | Bytecode.Send_message(pid, _) 115 | | Bytecode.Spawn(pid, _, _) => 116 | let {Process.Pid.scheduler_id, _} = pid |> Process.Pid.view; 117 | scheduler.unix_pid |> Int32.of_int |> Int32.equal(scheduler_id); 118 | }; 119 | }; 120 | 121 | let handle_coordinator_task = (scheduler, `From_coordinator(task)) => { 122 | switch (should_handle_task_locally(scheduler, task), task) { 123 | | (true, Bytecode.Send_message(pid, msg)) => 124 | handle_send_message(scheduler, pid, msg) 125 | | (true, Bytecode.Spawn(pid, proc, state)) => 126 | handle_spawn(scheduler, pid, proc, state) 127 | | (false, Bytecode.Halt) => handle_halt(scheduler) 128 | | (_, _) => () 129 | }; 130 | }; 131 | 132 | let handle_scheduler_task = 133 | (scheduler, `Write(to_parent), `From_scheduler(task)) => { 134 | switch (should_handle_task_locally(scheduler, task), task) { 135 | | (true, Bytecode.Send_message(pid, msg)) => 136 | handle_send_message(scheduler, pid, msg) 137 | | (true, Bytecode.Spawn(pid, proc, state)) => 138 | handle_spawn(scheduler, pid, proc, state) 139 | | (false, Bytecode.Halt as task) => 140 | handle_halt(scheduler); 141 | Coordinator.send_task(task, to_parent); 142 | | (_, task) => Coordinator.send_task(task, to_parent) 143 | }; 144 | }; 145 | 146 | let handle_task = (scheduler, `Write(_) as fd, task) => { 147 | switch (task) { 148 | | `From_coordinator(_) as task => handle_coordinator_task(scheduler, task) 149 | | `From_scheduler(_) as task => handle_scheduler_task(scheduler, fd, task) 150 | | `Reduction(f) => f() 151 | }; 152 | }; 153 | 154 | let run = (`Write(to_parent), `Read(from_parent), scheduler) => { 155 | Logs.info(m => m("[%d] Beginning scheduler loop...", scheduler.unix_pid)); 156 | let rec do_loop = () => { 157 | switch (scheduler.should_halt^) { 158 | | true => () 159 | | _ => 160 | let pid = scheduler.unix_pid; 161 | 162 | Logs.debug(m => 163 | m( 164 | "[%i] Tasks queue has %d tasks", 165 | pid, 166 | scheduler.tasks |> Task_queue.length, 167 | ) 168 | ); 169 | 170 | let (`Read(read_fds), `Write(write_fds), _) = 171 | Platform.Process.select( 172 | ~read=[from_parent], 173 | ~write=[to_parent], 174 | ~except=[], 175 | ~timeout=-1.0, 176 | ); 177 | 178 | switch (Task_queue.next(scheduler.tasks), write_fds) { 179 | | (Some(task), [fd]) => 180 | Logs.debug(m => m("[%i] Handling tasks...", pid)); 181 | handle_task(scheduler, `Write(fd), task); 182 | | _ => Logs.debug(m => m("[%i] No tasks to send. Standing by.", pid)) 183 | }; 184 | 185 | switch (read_fds) { 186 | | [fd] => 187 | Logs.debug(m => m("[%i] Receiving tasks...", pid)); 188 | switch (Coordinator.read_task(`Read(fd))) { 189 | | None => () 190 | | Some(task) => enqueue(scheduler, `From_coordinator(task)) 191 | }; 192 | | _ => () 193 | }; 194 | 195 | Lwt_engine.iter(false); 196 | 197 | do_loop(); 198 | }; 199 | }; 200 | switch (do_loop()) { 201 | | exception e => 202 | Logs.err(m => { 203 | let err = Printexc.to_string(e); 204 | m("[%i] Uncaught exception in scheduler: %s", scheduler.unix_pid, err); 205 | }) 206 | | _ => () 207 | }; 208 | }; 209 | -------------------------------------------------------------------------------- /src/scheduler/scheduler.rei: -------------------------------------------------------------------------------- 1 | type t; 2 | 3 | type task = [ 4 | | `From_coordinator(Bytecode.t) 5 | | `From_scheduler(Bytecode.t) 6 | | `Reduction(unit => unit) 7 | ]; 8 | 9 | let id: t => int; 10 | 11 | let last_pid: t => Process.Pid.t; 12 | 13 | let next_pid: t => Process.Pid.t; 14 | 15 | let current: unit => option(t); 16 | 17 | let is_scheduler: unit => bool; 18 | 19 | let enqueue: (t, task) => unit; 20 | 21 | let halt: t => unit; 22 | 23 | let setup: 24 | (~pid: int, [< | `Write(Unix.file_descr)], [< | `Read(Unix.file_descr)]) => 25 | t; 26 | 27 | let run: 28 | ([< | `Write(Unix.file_descr)], [< | `Read(Unix.file_descr)], t) => unit; 29 | -------------------------------------------------------------------------------- /src/task_queue/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name task_queue) 3 | (public_name reactor.task_queue)) 4 | -------------------------------------------------------------------------------- /src/task_queue/task_queue.re: -------------------------------------------------------------------------------- 1 | type t('a) = Queue.t('a); 2 | 3 | let create = Queue.create; 4 | 5 | let queue = (q, el) => Queue.add(el, q); 6 | 7 | let next = q => { 8 | switch (Queue.pop(q)) { 9 | | exception _ => None 10 | | el => Some(el) 11 | }; 12 | }; 13 | 14 | let to_seq = Queue.to_seq; 15 | 16 | let length = Queue.length; 17 | 18 | let clear = q => Queue.clear(q); 19 | -------------------------------------------------------------------------------- /src/task_queue/task_queue.rei: -------------------------------------------------------------------------------- 1 | type t('a); 2 | 3 | let create: unit => t('a); 4 | 5 | let queue: (t('a), 'a) => unit; 6 | 7 | let next: t('a) => option('a); 8 | 9 | let to_seq: t('a) => Seq.t('a); 10 | 11 | let length: t('a) => int; 12 | 13 | let clear: t('a) => unit; 14 | -------------------------------------------------------------------------------- /src/tasks/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name tasks) 3 | (public_name reactor.tasks) 4 | (libraries reactor.node)) 5 | -------------------------------------------------------------------------------- /src/tasks/tasks.re: -------------------------------------------------------------------------------- 1 | module Node = Node; 2 | module Task_queue = Task_queue; 3 | module Scheduler = Scheduler; 4 | module Bytecode = Bytecode; 5 | module Process = Process; 6 | 7 | let send = (pid, msg) => { 8 | let msg = Bytecode.Send_message(pid, msg); 9 | switch (Node.role()) { 10 | | `Scheduler(s) => Scheduler.enqueue(s, `From_scheduler(msg)) 11 | | `Node(n) => Node.enqueue(n, msg) 12 | }; 13 | }; 14 | 15 | let (<-) = send; 16 | 17 | let spawn_from_coordinator = (node, task, state) => { 18 | let least_busy_scheduler = node |> Node.least_busy_scheduler; 19 | 20 | let pid = 21 | switch (least_busy_scheduler) { 22 | | Some(scheduler) => 23 | let pid = Node.next_pid(node, scheduler); 24 | Node.enqueue(node, Bytecode.Spawn(pid, task, state)); 25 | pid; 26 | | None => Process.Pid.make(0, 0, 0) 27 | }; 28 | 29 | pid; 30 | }; 31 | 32 | let spawn_in_scheduler = (scheduler, task, state) => { 33 | let pid = Scheduler.next_pid(scheduler); 34 | let msg = Bytecode.Spawn(pid, task, state); 35 | Scheduler.enqueue(scheduler, `From_scheduler(msg)); 36 | pid; 37 | }; 38 | 39 | let spawn = (task, state) => { 40 | let pid = 41 | switch (Node.role()) { 42 | | `Scheduler(scheduler) => spawn_in_scheduler(scheduler, task, state) 43 | | `Node(node) => spawn_from_coordinator(node, task, state) 44 | }; 45 | pid; 46 | }; 47 | 48 | let halt = () => { 49 | Logs.debug(m => m("[%d] Shutting down...", Platform.Process.pid())); 50 | switch (Node.role()) { 51 | | `Scheduler(scheduler) => Scheduler.halt(scheduler) 52 | | `Node(node) => Node.halt(node) 53 | }; 54 | }; 55 | 56 | let exit = () => { 57 | halt(); 58 | `Terminate; 59 | }; 60 | -------------------------------------------------------------------------------- /src/tasks/tasks.rei: -------------------------------------------------------------------------------- 1 | let send: (Process.Pid.t, string) => unit; 2 | 3 | let (<-): (Process.Pid.t, string) => unit; 4 | 5 | let spawn: (Process.task('a), 'a) => Process.Pid.t; 6 | 7 | let halt: unit => unit; 8 | 9 | let exit: unit => [> | `Terminate]; 10 | -------------------------------------------------------------------------------- /test/dune: -------------------------------------------------------------------------------- 1 | (tests 2 | (names runtime_test) 3 | (libraries reactor alcotest)) 4 | -------------------------------------------------------------------------------- /test/process/dune: -------------------------------------------------------------------------------- 1 | (tests 2 | (names pid_test) 3 | (libraries reactor qcheck qcheck-alcotest alcotest)) 4 | -------------------------------------------------------------------------------- /test/process/pid_test.re: -------------------------------------------------------------------------------- 1 | open Reactor; 2 | 3 | let count = 1000; 4 | 5 | let pid = { 6 | let of_triple = ((n, w, p)) => Pid.make(n, w, p); 7 | let pid_gen = QCheck.Gen.(triple(int, int, int) >|= of_triple); 8 | QCheck.make(pid_gen); 9 | }; 10 | 11 | let pid_equality = { 12 | let prop = p => Pid.equal(p, p) == true; 13 | QCheck.Test.make(~count, ~name="a pid is equal to itself", pid, prop); 14 | }; 15 | 16 | let next_pid_is_not_same_pid = { 17 | let prop = p => Pid.equal(p, p |> Pid.next) == false; 18 | QCheck.Test.make(~count, ~name="next pid is not same pid", pid, prop); 19 | }; 20 | 21 | let view_is_consistent = { 22 | let prop = p => { 23 | let v = Pid.view(p); 24 | let p' = 25 | Pid.make( 26 | v.node_id |> Int32.to_int, 27 | v.scheduler_id |> Int32.to_int, 28 | v.process_id |> Int32.to_int, 29 | ); 30 | let v' = Pid.view(p'); 31 | v == v'; 32 | }; 33 | QCheck.Test.make( 34 | ~count, 35 | ~name="a pid is consistent with it's view", 36 | pid, 37 | prop, 38 | ); 39 | }; 40 | 41 | let suite = 42 | List.map( 43 | QCheck_alcotest.to_alcotest, 44 | [pid_equality, next_pid_is_not_same_pid, view_is_consistent], 45 | ); 46 | 47 | let () = Alcotest.run("Model.Pid", [("core", suite)]); 48 | -------------------------------------------------------------------------------- /test/runtime_test.re: -------------------------------------------------------------------------------- 1 | open Reactor.System; 2 | 3 | let become_reduction = () => { 4 | Reactor.Node.(Policy.default() |> setup); 5 | 6 | let _ = 7 | spawn( 8 | (_, count) => 9 | switch (count) { 10 | | x when x == 0 => exit() 11 | | _ => `Become(count - 1) 12 | }, 13 | 5, 14 | ); 15 | 16 | Reactor.Node.run(); 17 | Alcotest.(check(bool, "", true, true)); 18 | }; 19 | 20 | let deferred_reduction = () => { 21 | Reactor.Node.(Policy.default() |> setup); 22 | 23 | let _ = 24 | spawn( 25 | (_, count) => 26 | switch (count) { 27 | | x when x == 0 => exit() 28 | | _ => 29 | let promise = Lwt_unix.sleep(0.2) |> Lwt.map(_ => count - 1); 30 | `Defer(promise); 31 | }, 32 | 5, 33 | ); 34 | 35 | Reactor.Node.run(); 36 | Alcotest.(check(bool, "", true, true)); 37 | }; 38 | 39 | let suite = [ 40 | ("Deferred reductions", `Slow, deferred_reduction), 41 | ("Become reductions", `Slow, become_reduction), 42 | ]; 43 | 44 | let () = Alcotest.run("Reactor", [("reductions", suite)]); 45 | -------------------------------------------------------------------------------- /tools/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name log_splitter) 3 | (libraries logs logs.fmt fmt fmt.tty)) 4 | -------------------------------------------------------------------------------- /tools/log_splitter.re: -------------------------------------------------------------------------------- 1 | module Matcher = { 2 | let pid = line => { 3 | let parts = String.split_on_char(' ', line) |> Array.of_list; 4 | parts[2]; 5 | }; 6 | }; 7 | 8 | module IO = { 9 | let read_lines = () => { 10 | let rec read = acc => { 11 | switch (input_line(stdin)) { 12 | | exception _ => acc |> List.rev 13 | | line => read([line, ...acc]) 14 | }; 15 | }; 16 | read([]); 17 | }; 18 | }; 19 | 20 | module Bucket = { 21 | module Table = 22 | Hashtbl.Make({ 23 | type t = string; 24 | let equal = String.equal; 25 | let hash = Hashtbl.hash; 26 | }); 27 | 28 | type t = Table.t(list(string)); 29 | 30 | let create: int => t = Table.create; 31 | 32 | let add = (t, line) => { 33 | let pid = Matcher.pid(line); 34 | let lines_for_pid = 35 | switch (Table.find_opt(t, pid)) { 36 | | Some(v) => v 37 | | None => [] 38 | }; 39 | Table.replace(t, pid, [line, ...lines_for_pid]); 40 | }; 41 | 42 | let dump = t => { 43 | Table.to_seq(t) 44 | |> List.of_seq 45 | |> List.sort(((p1, _), (p2, _)) => String.compare(p1, p2)) 46 | |> List.iter(((pid, lines)) => { 47 | Printf.printf("Process %s: \n", pid); 48 | lines |> List.rev |> List.iter(line => Printf.printf("%s\n%!", line)); 49 | Printf.printf("\n"); 50 | }); 51 | }; 52 | }; 53 | 54 | let () = { 55 | let lines = IO.read_lines(); 56 | let bucket = Bucket.create(1024); 57 | lines |> List.iter(Bucket.add(bucket)); 58 | Bucket.dump(bucket); 59 | }; 60 | --------------------------------------------------------------------------------