P35HCXDOT4NKKPTM6OMKEVKBLB3VLEODS7LNKRG7777RLOFDGU2AC
open Containers
module P = struct
open Angstrom
let is_ws = function ' ' | '\t' | '\n' -> true | _ -> false
let ws = skip_while is_ws
let cmd prefix =
let* name = ws *> string prefix *> take_till is_ws <* ws in
let+ args = many any_char <* end_of_input >>| String.of_list in
(name, args)
end
let parse = Angstrom.parse_string ~consume:Angstrom.Consume.All
let of_message ~prefix msg =
match parse (P.cmd prefix) msg with Error _ -> None | Ok cmd -> Some cmd
open Containers
type t = { token : string; prefix : string }
let token { token; _ } = token
let prefix { prefix; _ } = prefix
let of_filename filename =
match Toml.Parser.from_filename filename with
| `Ok tbl ->
let open Result in
let+ token =
Toml.Lenses.(get tbl (key "auth" |-- table |-- key "token" |-- string))
|> Option.to_result_lazy (fun () ->
Format.asprintf "Invalid configuration: missing [auth.token]@.")
in
let prefix =
Toml.Lenses.(
get tbl (key "commands" |-- table |-- key "prefix" |-- string))
|> Option.get_or ~default:"!"
in
{ token; prefix }
| `Error (_, loc) ->
Error
(Format.asprintf
"Invalid TOML in configuration: @[file='%s'@] @[line=%d@] \
@[column=%d@]@."
filename loc.line loc.column)
module Config = struct
type t = { token : string; prefix : string }
let token { token; _ } = token
let prefix { prefix; _ } = prefix
let of_filename filename =
match Toml.Parser.from_filename filename with
| `Ok tbl ->
let open Result in
let+ token =
Toml.Lenses.(
get tbl (key "auth" |-- table |-- key "token" |-- string))
|> Option.to_result_lazy (fun () ->
Format.asprintf "Invalid configuration: missing [auth.token]@.")
in
let prefix =
Toml.Lenses.(
get tbl (key "commands" |-- table |-- key "prefix" |-- string))
|> Option.get_or ~default:"!"
in
{ token; prefix }
| `Error (_, loc) ->
Error
(Format.asprintf
"Invalid TOML in configuration: @[file='%s'@] @[line=%d@] \
@[column=%d@]@."
filename loc.line loc.column)
end
let is_ws = function ' ' | '\t' | '\n' -> true | _ -> false
let ws = skip_while is_ws
let cmd prefix =
let* name = ws *> string prefix *> take_till is_ws <* ws in
let+ args = many any_char <* end_of_input >>| String.of_list in
(name, args)
end
let parse = Angstrom.parse_string ~consume:Angstrom.Consume.All
let of_message ~prefix msg =
match parse (P.cmd prefix) msg with Error _ -> None | Ok cmd -> Some cmd
end
| Some ("join", "") ->
let msg =
Msg.fmt
"⚠️ Not supported yet, please provide a voice channel id"
in
D.Client.send_message channel_id msg client
| Some ("join", v_channel_id) ->
let guild_id = Option.get_exn guild_id in
let v_channel_id = M.Snowflake.of_string v_channel_id in
D.Client.join_voice ~guild_id ~channel_id:v_channel_id client
| Some ("play", "kiff") -> (
let guild_id = Option.get_exn guild_id in
let* s = D.Audio_stream.Ffmpeg.of_file "./kiff.mp3" in
match s with
| Ok audio_stream ->
D.Client.play_audio_stream ~guild_id audio_stream client
| _ -> Lwt.return_unit)
| Some ("play", "soundbite") -> (
let guild_id = Option.get_exn guild_id in
let* s = D.Audio_stream.Ffmpeg.of_file "./bite2.mp3" in
match s with
| Ok audio_stream ->
D.Client.play_audio_stream ~guild_id audio_stream client
| _ -> Lwt.return_unit)
(executable
(name discopotty)
(public_name discopotty)
(libraries discord containers toml relog.lib angstrom))
open Containers
let work () =
let sine_stream = Discord.Audio_stream.Gen.sine ~freq:1000 3. in
let buf = Bigstringaf.create (960 * 2 * 4) in
let fill_buff frame =
let f = Faraday.create (1024 * 4) in
Seq.(
0 --^ Bigarray.Array1.dim frame
|> iter (fun i -> Faraday.LE.write_float f frame.{i}));
Faraday.serialize_to_bigstring f
in
sine_stream
|> Lwt_pipe.Reader.iter_s ~f:(fun frame ->
Lwt_io.write_from_exactly_bigstring Lwt_io.stdout (fill_buff frame) 0
(Bigstringaf.length buf))
(* let () = Lwt_main.run (work ())*)
*** DONE Investigate EOF reason in websockets
WebsocketAF was the issue: fixed parser buffer size of 4kb
(when =GUILD_READY= payloads can go well over that size)
Submitted a PR [[https://github.com/anmonteiro/websocketaf/pull/25][here]]
* TODO Sharding
First should actually research how to do it in a worthwhile way
+(since we are essencially stuck in single-threaded mode for now)+
[2021-2-23 Tue] /Nevermind: Sharding is useful if only to decrease rate limiting bottlenecks./
** TODO Identify Concurrency handling
A global lock/token bucket should suffice.
Maybe make it a map of ~(bot token)->(token bucket)~ in case the user
wants to run multiple different bots in a single application.
* DONE Voice Connection
** DONE Voice Gateway Protocol
*** DONE IP Discovery
** DONE Voice UDP
*** DONE Test soundbite
-------
* TODO Music Player
** TODO Replace external ffmpeg/ffprobe process with libav
- Will this be a PITA because of all the needed codecs
when building? /probably/
- Is it worth it? /no/ (maybe it's actually worse given that ocaml-multicore isn't here yet 😿)
- Is it fun? /yeah/ 😝
* DOING Voice connection
** DOING Voice Gateway
** TODO Voice UDP
*** TODO Test soundbite
I think hardcoding some bytes in the code
should suffice for now
** TODO youtube-dl support
** TODO Custom ytdl-like implementation
I reckon this is really only worth it if we do the libav thing.
-------
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"esy-libsodium@archive:https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz#sha1:795b73e3f92a362fabee238a71735579bf46bb97@a5898027": {
"id":
"esy-libsodium@archive:https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz#sha1:795b73e3f92a362fabee238a71735579bf46bb97@a5898027",
"name": "esy-libsodium",
"version":
"archive:https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz#sha1:795b73e3f92a362fabee238a71735579bf46bb97",
"source": {
"type": "install",
"source": [
"archive:https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz#sha1:795b73e3f92a362fabee238a71735579bf46bb97"
]
},
"overrides": [ "esy.lock/overrides/a589802762d4c745d460324213040534" ],
"dependencies": [],
"devDependencies": []
},
"esy-libopus@archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b@24aa01e3": {
"id":
"esy-libopus@archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b@24aa01e3",
"name": "esy-libopus",
"version":
"archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b",
"source": {
"type": "install",
"source": [
"archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b"
]
},
"overrides": [ "vendor/esy-libopus/package.json" ],
"dependencies": [
"@opam/conf-pkg-config@opam:1.3@93481236",
"@opam/conf-autoconf@github:esy-packages/esy-autoconf:package.json#fb93edf@d41d8cd9"
],
"devDependencies": []
},
"esy-libffi@github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c@d41d8cd9": {
"id":
"esy-libffi@github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c@d41d8cd9",
"name": "esy-libffi",
"version":
"github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c",
"source": {
"type": "install",
"source": [
"github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c"
"ocaml@4.11.1000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/websocketaf-lwt-unix@link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf-lwt-unix.opam",
"@opam/websocketaf@link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf.opam",
"ocaml@4.11.2000@d41d8cd9",
"esy-libsodium@archive:https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz#sha1:795b73e3f92a362fabee238a71735579bf46bb97@a5898027",
"@opam/yojson@opam:1.7.0@7056d985",
"@opam/websocketaf-lwt-unix@github:quartz55/websocketaf:websocketaf-lwt-unix.opam#d309d15@d41d8cd9",
"@opam/websocketaf@github:quartz55/websocketaf:websocketaf.opam#d309d15@d41d8cd9",
"@opam/zed@opam:3.1.0@86c55416": {
"id": "@opam/zed@opam:3.1.0@86c55416",
"name": "@opam/zed",
"version": "opam:3.1.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/51/51e8676ba972e5ad727633c161e404b1#md5:51e8676ba972e5ad727633c161e404b1",
"archive:https://github.com/ocaml-community/zed/archive/3.1.0.tar.gz#md5:51e8676ba972e5ad727633c161e404b1"
],
"opam": {
"name": "zed",
"version": "3.1.0",
"path": "esy.lock/opam/zed.3.1.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/react@opam:1.2.1@0e11855f",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/charInfo_width@opam:1.1.0@4296bdfe",
"@opam/camomile@opam:1.0.2@40411a6b",
"@opam/base-bytes@opam:base@19d0c2ff",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/react@opam:1.2.1@0e11855f",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/charInfo_width@opam:1.1.0@4296bdfe",
"@opam/camomile@opam:1.0.2@40411a6b",
"@opam/base-bytes@opam:base@19d0c2ff"
]
},
"ocaml@4.11.1000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.2@3d714e5f", "@opam/cppo@opam:1.6.7@c28ac3ae",
"ocaml@4.11.2000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/cppo@opam:1.6.7@c28ac3ae",
"ocaml@4.11.1000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.2@3d714e5f", "@opam/biniou@opam:1.2.1@d7570399"
"ocaml@4.11.2000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/biniou@opam:1.2.1@d7570399"
"ocaml@4.11.1000@d41d8cd9",
"@opam/websocketaf-lwt@link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf-lwt.opam",
"@opam/websocketaf@link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf.opam",
"ocaml@4.11.2000@d41d8cd9",
"@opam/websocketaf-lwt@github:quartz55/websocketaf:websocketaf-lwt.opam#d309d15@d41d8cd9",
"@opam/websocketaf@github:quartz55/websocketaf:websocketaf.opam#d309d15@d41d8cd9",
"ocaml@4.11.1000@d41d8cd9",
"@opam/websocketaf-lwt@link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf-lwt.opam",
"@opam/websocketaf@link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf.opam",
"ocaml@4.11.2000@d41d8cd9",
"@opam/websocketaf-lwt@github:quartz55/websocketaf:websocketaf-lwt.opam#d309d15@d41d8cd9",
"@opam/websocketaf@github:quartz55/websocketaf:websocketaf.opam#d309d15@d41d8cd9",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/utop@opam:2.7.0@4ba5133d": {
"id": "@opam/utop@opam:2.7.0@4ba5133d",
"name": "@opam/utop",
"version": "opam:2.7.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/e0/e068ac53df267c3cc0f2f69bbc204404f0362cc4e6472a1fc547e326a63c3fdd#sha256:e068ac53df267c3cc0f2f69bbc204404f0362cc4e6472a1fc547e326a63c3fdd",
"archive:https://github.com/ocaml-community/utop/releases/download/2.7.0/utop-2.7.0.tbz#sha256:e068ac53df267c3cc0f2f69bbc204404f0362cc4e6472a1fc547e326a63c3fdd"
],
"opam": {
"name": "utop",
"version": "2.7.0",
"path": "esy.lock/opam/utop.2.7.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/react@opam:1.2.1@0e11855f",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/lwt_react@opam:1.1.4@7d2054d1",
"@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/lambda-term@opam:3.1.0@8adc2660",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/cppo@opam:1.6.7@c28ac3ae",
"@opam/camomile@opam:1.0.2@40411a6b",
"@opam/base-unix@opam:base@87d0b2eb",
"@opam/base-threads@opam:base@36803084",
"devDependencies": [ "ocaml@4.11.1000@d41d8cd9" ]
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/react@opam:1.2.1@0e11855f",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/lwt_react@opam:1.1.4@7d2054d1",
"@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/lambda-term@opam:3.1.0@8adc2660",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/camomile@opam:1.0.2@40411a6b",
"@opam/base-unix@opam:base@87d0b2eb",
"@opam/base-threads@opam:base@36803084"
]
"@opam/dune@opam:2.8.2@3d714e5f"
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/trie@opam:1.0.0@d2efc587": {
"id": "@opam/trie@opam:1.0.0@d2efc587",
"name": "@opam/trie",
"version": "opam:1.0.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/84/84519b5f8bd92490bfc68a52f706ba14#md5:84519b5f8bd92490bfc68a52f706ba14",
"archive:https://github.com/kandu/trie/archive/1.0.0.tar.gz#md5:84519b5f8bd92490bfc68a52f706ba14"
],
"opam": {
"name": "trie",
"version": "1.0.0",
"path": "esy.lock/opam/trie.1.0.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
"@opam/stdint@opam:0.7.0@f8c664d1": {
"id": "@opam/stdint@opam:0.7.0@f8c664d1",
"name": "@opam/stdint",
"version": "opam:0.7.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/4f/4fcc66aef58e2b96e7af3bbca9d910aa239e045ba5fb2400aaef67d0041252dc#sha256:4fcc66aef58e2b96e7af3bbca9d910aa239e045ba5fb2400aaef67d0041252dc",
"archive:https://github.com/andrenth/ocaml-stdint/releases/download/0.7.0/stdint-0.7.0.tbz#sha256:4fcc66aef58e2b96e7af3bbca9d910aa239e045ba5fb2400aaef67d0041252dc"
],
"opam": {
"name": "stdint",
"version": "0.7.0",
"path": "esy.lock/opam/stdint.0.7.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/sodium@github:quartz55/ocaml-sodium:sodium.opam#6088c1c@32227790": {
"id":
"@opam/sodium@github:quartz55/ocaml-sodium:sodium.opam#6088c1c@32227790",
"name": "@opam/sodium",
"version": "github:quartz55/ocaml-sodium:sodium.opam#6088c1c",
"source": {
"type": "install",
"source": [ "github:quartz55/ocaml-sodium:sodium.opam#6088c1c" ]
},
"overrides": [ { "dependencies": { "@opam/conf-libsodium": "*" } } ],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/ctypes@opam:0.18.0@1be5c5e5",
"@opam/conf-libsodium@github:EduardoRFS/esy-libsodium:libsodium.opam#caeedd7@d003f610",
"@opam/base-bytes@opam:base@19d0c2ff",
"@opam/base-bigarray@opam:base@b03491b0",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ctypes@opam:0.18.0@1be5c5e5",
"@opam/base-bytes@opam:base@19d0c2ff",
"@opam/base-bigarray@opam:base@b03491b0"
]
},
},
"@opam/react@opam:1.2.1@0e11855f": {
"id": "@opam/react@opam:1.2.1@0e11855f",
"name": "@opam/react",
"version": "opam:1.2.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/ce/ce1454438ce4e9d2931248d3abba1fcc#md5:ce1454438ce4e9d2931248d3abba1fcc",
"archive:http://erratique.ch/software/react/releases/react-1.2.1.tbz#md5:ce1454438ce4e9d2931248d3abba1fcc"
],
"opam": {
"name": "react",
"version": "1.2.1",
"path": "esy.lock/opam/react.1.2.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/topkg@opam:1.0.3@e4e10f1c",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
"ocaml@4.11.1000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.1000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.1000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.1000@d41d8cd9", "@opam/dune@opam:2.8.2@3d714e5f"
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/ppx_cstubs@opam:0.6.1.1@706c3a9f": {
"id": "@opam/ppx_cstubs@opam:0.6.1.1@706c3a9f",
"name": "@opam/ppx_cstubs",
"version": "opam:0.6.1.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/33/33e520e369da5630c697318f6f4ed26d#md5:33e520e369da5630c697318f6f4ed26d",
"archive:https://github.com/fdopen/ppx_cstubs/archive/0.6.1.1.tar.gz#md5:33e520e369da5630c697318f6f4ed26d"
],
"opam": {
"name": "ppx_cstubs",
"version": "0.6.1.1",
"path": "esy.lock/opam/ppx_cstubs.0.6.1.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/re@opam:1.9.0@d4d5e13d", "@opam/ppxlib@opam:0.22.0@d2d2223a",
"@opam/ocamlfind@opam:1.8.1@b7dc3072", "@opam/num@opam:1.4@a5195c8d",
"@opam/integers@opam:0.4.0@f7acfaeb",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/ctypes@opam:0.18.0@1be5c5e5",
"@opam/cppo@opam:1.6.7@c28ac3ae",
"@opam/containers@opam:3.2@c4e3f662",
"@opam/bigarray-compat@opam:1.0.0@3a87ad65",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/re@opam:1.9.0@d4d5e13d", "@opam/ppxlib@opam:0.22.0@d2d2223a",
"@opam/ocamlfind@opam:1.8.1@b7dc3072", "@opam/num@opam:1.4@a5195c8d",
"@opam/integers@opam:0.4.0@f7acfaeb",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/ctypes@opam:0.18.0@1be5c5e5",
"@opam/containers@opam:3.2@c4e3f662",
"@opam/bigarray-compat@opam:1.0.0@3a87ad65"
"archive:https://opam.ocaml.org/cache/sha256/24/24b2f324ea91cff98bb8790a6746ccce3173bac5f57cb457156e5c50a0467397#sha256:24b2f324ea91cff98bb8790a6746ccce3173bac5f57cb457156e5c50a0467397",
"archive:https://github.com/ocurrent/ocaml-version/releases/download/v3.0.0/ocaml-version-v3.0.0.tbz#sha256:24b2f324ea91cff98bb8790a6746ccce3173bac5f57cb457156e5c50a0467397"
"archive:https://opam.ocaml.org/cache/sha256/ac/ac7ba16a09d8f72212742f3936980fbfaebb698c7bbf625182af7d6b2c3cde5f#sha256:ac7ba16a09d8f72212742f3936980fbfaebb698c7bbf625182af7d6b2c3cde5f",
"archive:https://github.com/ocurrent/ocaml-version/releases/download/v3.1.0/ocaml-version-v3.1.0.tbz#sha256:ac7ba16a09d8f72212742f3936980fbfaebb698c7bbf625182af7d6b2c3cde5f"
"@opam/num@opam:1.4@a5195c8d": {
"id": "@opam/num@opam:1.4@a5195c8d",
"name": "@opam/num",
"version": "opam:1.4",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/cd/cda2b727e116a0b6a9c03902cc4b2415#md5:cda2b727e116a0b6a9c03902cc4b2415",
"archive:https://github.com/ocaml/num/archive/v1.4.tar.gz#md5:cda2b727e116a0b6a9c03902cc4b2415"
],
"opam": {
"name": "num",
"version": "1.4",
"path": "esy.lock/opam/num.1.4"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__num_opam__c__1.4_opam_override"
}
],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"ocaml@4.11.1000@d41d8cd9", "@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/mew_vi@opam:0.5.0@cf66c299": {
"id": "@opam/mew_vi@opam:0.5.0@cf66c299",
"name": "@opam/mew_vi",
"version": "opam:0.5.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/34/341e9a9a20383641015bf503952906bc#md5:341e9a9a20383641015bf503952906bc",
"archive:https://github.com/kandu/mew_vi/archive/0.5.0.tar.gz#md5:341e9a9a20383641015bf503952906bc"
],
"opam": {
"name": "mew_vi",
"version": "0.5.0",
"path": "esy.lock/opam/mew_vi.0.5.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/react@opam:1.2.1@0e11855f",
"@opam/mew@opam:0.1.0@a74f69d6", "@opam/dune@opam:2.8.4@ee414d6c",
"ocaml@4.11.1000@d41d8cd9", "@opam/dune@opam:2.8.2@3d714e5f"
"ocaml@4.11.2000@d41d8cd9", "@opam/react@opam:1.2.1@0e11855f",
"@opam/mew@opam:0.1.0@a74f69d6", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/mew@opam:0.1.0@a74f69d6": {
"id": "@opam/mew@opam:0.1.0@a74f69d6",
"name": "@opam/mew",
"version": "opam:0.1.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/22/2298149d1415cd804ab4e01f01ea10a0#md5:2298149d1415cd804ab4e01f01ea10a0",
"archive:https://github.com/kandu/mew/archive/0.1.0.tar.gz#md5:2298149d1415cd804ab4e01f01ea10a0"
],
"opam": {
"name": "mew",
"version": "0.1.0",
"path": "esy.lock/opam/mew.0.1.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/trie@opam:1.0.0@d2efc587",
"@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/trie@opam:1.0.0@d2efc587",
"@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.4@ee414d6c"
"ocaml@4.11.1000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.4@ee414d6c",
"ocaml@4.11.1000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.4@ee414d6c",
"archive:https://opam.ocaml.org/cache/md5/f2/f27f8f5dedd316eff4c02d9130fced49#md5:f27f8f5dedd316eff4c02d9130fced49",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20201216/archive.tar.gz#md5:f27f8f5dedd316eff4c02d9130fced49"
"archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"archive:https://opam.ocaml.org/cache/md5/f2/f27f8f5dedd316eff4c02d9130fced49#md5:f27f8f5dedd316eff4c02d9130fced49",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20201216/archive.tar.gz#md5:f27f8f5dedd316eff4c02d9130fced49"
"archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"archive:https://opam.ocaml.org/cache/md5/f2/f27f8f5dedd316eff4c02d9130fced49#md5:f27f8f5dedd316eff4c02d9130fced49",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20201216/archive.tar.gz#md5:f27f8f5dedd316eff4c02d9130fced49"
"archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"ocaml@4.11.1000@d41d8cd9", "@opam/menhirSdk@opam:20201216@5e08e674",
"@opam/menhirLib@opam:20201216@bb5a1851",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/menhirSdk@opam:20210310@5abaafca",
"@opam/menhirLib@opam:20210310@f9315713",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.1000@d41d8cd9", "@opam/menhirSdk@opam:20201216@5e08e674",
"@opam/menhirLib@opam:20201216@bb5a1851",
"@opam/dune@opam:2.8.2@3d714e5f"
"ocaml@4.11.2000@d41d8cd9", "@opam/menhirSdk@opam:20210310@5abaafca",
"@opam/menhirLib@opam:20210310@f9315713",
"@opam/dune@opam:2.8.4@ee414d6c"
"ocaml@4.11.1000@d41d8cd9", "@opam/ssl@opam:0.5.10@ae7a31df",
"@opam/lwt@opam:5.4.0@1ec6dbfd", "@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/ssl@opam:0.5.10@ae7a31df",
"@opam/lwt@opam:5.4.0@1ec6dbfd", "@opam/dune@opam:2.8.4@ee414d6c",
"ocaml@4.11.1000@d41d8cd9", "@opam/ssl@opam:0.5.10@ae7a31df",
"@opam/lwt@opam:5.4.0@1ec6dbfd", "@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/ssl@opam:0.5.10@ae7a31df",
"@opam/lwt@opam:5.4.0@1ec6dbfd", "@opam/dune@opam:2.8.4@ee414d6c",
"@opam/lwt_react@opam:1.1.4@7d2054d1": {
"id": "@opam/lwt_react@opam:1.1.4@7d2054d1",
"name": "@opam/lwt_react",
"version": "opam:1.1.4",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/fc/fc4721bdb1a01225b96e3a2debde95fa#md5:fc4721bdb1a01225b96e3a2debde95fa",
"archive:https://github.com/ocsigen/lwt/archive/5.4.0.zip#md5:fc4721bdb1a01225b96e3a2debde95fa"
],
"opam": {
"name": "lwt_react",
"version": "1.1.4",
"path": "esy.lock/opam/lwt_react.1.1.4"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/react@opam:1.2.1@0e11855f",
"@opam/lwt@opam:5.4.0@1ec6dbfd", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/react@opam:1.2.1@0e11855f",
"@opam/lwt@opam:5.4.0@1ec6dbfd", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/lwt_log@opam:1.1.1@2d7a797f": {
"id": "@opam/lwt_log@opam:1.1.1@2d7a797f",
"name": "@opam/lwt_log",
"version": "opam:1.1.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/02/02e93be62288037870ae5b1ce099fe59#md5:02e93be62288037870ae5b1ce099fe59",
"archive:https://github.com/aantron/lwt_log/archive/1.1.1.tar.gz#md5:02e93be62288037870ae5b1ce099fe59"
],
"opam": {
"name": "lwt_log",
"version": "1.1.1",
"path": "esy.lock/opam/lwt_log.1.1.1"
}
},
"overrides": [],
"dependencies": [
"@opam/lwt@opam:5.4.0@1ec6dbfd", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"@opam/lwt@opam:5.4.0@1ec6dbfd", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"ocaml@4.11.1000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/lambda-term@opam:3.1.0@8adc2660": {
"id": "@opam/lambda-term@opam:3.1.0@8adc2660",
"name": "@opam/lambda-term",
"version": "opam:3.1.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/78/78180c04ecfc8060b23d7d0014f24196#md5:78180c04ecfc8060b23d7d0014f24196",
"archive:https://github.com/ocaml-community/lambda-term/archive/3.1.0.tar.gz#md5:78180c04ecfc8060b23d7d0014f24196"
],
"opam": {
"name": "lambda-term",
"version": "3.1.0",
"path": "esy.lock/opam/lambda-term.3.1.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/zed@opam:3.1.0@86c55416",
"@opam/react@opam:1.2.1@0e11855f",
"@opam/mew_vi@opam:0.5.0@cf66c299",
"@opam/lwt_react@opam:1.1.4@7d2054d1",
"@opam/lwt_log@opam:1.1.1@2d7a797f", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/camomile@opam:1.0.2@40411a6b",
"devDependencies": [ "ocaml@4.11.1000@d41d8cd9" ]
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/zed@opam:3.1.0@86c55416",
"@opam/react@opam:1.2.1@0e11855f",
"@opam/mew_vi@opam:0.5.0@cf66c299",
"@opam/lwt_react@opam:1.1.4@7d2054d1",
"@opam/lwt_log@opam:1.1.1@2d7a797f", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/camomile@opam:1.0.2@40411a6b"
]
},
"@opam/integers@opam:0.4.0@f7acfaeb": {
"id": "@opam/integers@opam:0.4.0@f7acfaeb",
"name": "@opam/integers",
"version": "opam:0.4.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/c1/c1492352e6525048790508c57aad93c3#md5:c1492352e6525048790508c57aad93c3",
"archive:https://github.com/ocamllabs/ocaml-integers/archive/0.4.0.tar.gz#md5:c1492352e6525048790508c57aad93c3"
],
"opam": {
"name": "integers",
"version": "0.4.0",
"path": "esy.lock/opam/integers.0.4.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/hxd@opam:0.3.1@a1c09d49": {
"id": "@opam/hxd@opam:0.3.1@a1c09d49",
"name": "@opam/hxd",
"version": "opam:0.3.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/1c/1c226c91e17cd329dec0c287bfd20f36302aa533069ff9c6ced32721f96b29bc#sha256:1c226c91e17cd329dec0c287bfd20f36302aa533069ff9c6ced32721f96b29bc",
"archive:https://github.com/dinosaure/hxd/releases/download/v0.3.1/hxd-v0.3.1.tbz#sha256:1c226c91e17cd329dec0c287bfd20f36302aa533069ff9c6ced32721f96b29bc"
],
"opam": {
"name": "hxd",
"version": "0.3.1",
"path": "esy.lock/opam/hxd.0.3.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/cmdliner@opam:1.0.4@93208aac",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/cmdliner@opam:1.0.4@93208aac"
]
"ocaml@4.11.1000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/gluten@opam:0.2.1@fca26440", "@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/gluten@opam:0.2.1@fca26440", "@opam/dune@opam:2.8.4@ee414d6c",
"ocaml@4.11.1000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/gluten@opam:0.2.1@fca26440", "@opam/dune@opam:2.8.2@3d714e5f"
"ocaml@4.11.2000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/gluten@opam:0.2.1@fca26440", "@opam/dune@opam:2.8.4@ee414d6c"
"ocaml@4.11.1000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/faraday@opam:0.7.2@5dfdf1f9", "@opam/dune@opam:2.8.2@3d714e5f"
"ocaml@4.11.2000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/faraday@opam:0.7.2@5dfdf1f9", "@opam/dune@opam:2.8.4@ee414d6c"
"archive:https://opam.ocaml.org/cache/sha256/e2/e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e#sha256:e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e",
"archive:https://github.com/ocaml/dune/releases/download/2.8.2/dune-2.8.2.tbz#sha256:e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e"
"archive:https://opam.ocaml.org/cache/sha256/4e/4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac",
"archive:https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"ocaml@4.11.1000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.2@3d714e5f", "@opam/csexp@opam:1.4.0@bd1cb034",
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/csexp@opam:1.4.0@bd1cb034",
"ocaml@4.11.1000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.2@3d714e5f", "@opam/csexp@opam:1.4.0@bd1cb034"
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/csexp@opam:1.4.0@bd1cb034"
"archive:https://opam.ocaml.org/cache/sha256/e2/e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e#sha256:e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e",
"archive:https://github.com/ocaml/dune/releases/download/2.8.2/dune-2.8.2.tbz#sha256:e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e"
"archive:https://opam.ocaml.org/cache/sha256/4e/4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac",
"archive:https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"archive:https://opam.ocaml.org/cache/sha256/e2/e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e#sha256:e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e",
"archive:https://github.com/ocaml/dune/releases/download/2.8.2/dune-2.8.2.tbz#sha256:e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e"
"archive:https://opam.ocaml.org/cache/sha256/4e/4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac",
"archive:https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"ocaml@4.11.1000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/eqaf@opam:0.7@e7d6447e", "@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/eqaf@opam:0.7@e7d6447e", "@opam/dune@opam:2.8.4@ee414d6c",
"ocaml@4.11.1000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/eqaf@opam:0.7@e7d6447e", "@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/eqaf@opam:0.7@e7d6447e", "@opam/dune@opam:2.8.4@ee414d6c",
},
"@opam/ctypes-foreign@opam:0.4.0@6d218780": {
"id": "@opam/ctypes-foreign@opam:0.4.0@6d218780",
"name": "@opam/ctypes-foreign",
"version": "opam:0.4.0",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "ctypes-foreign",
"version": "0.4.0",
"path": "esy.lock/opam/ctypes-foreign.0.4.0"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__ctypes_foreign_opam__c__0.4.0_opam_override"
}
],
"dependencies": [
"@opam/conf-libffi@opam:2.0.0@7c8981c5",
"@esy-ocaml/substs@0.0.1@d41d8cd9",
"@esy-ocaml/libffi@3.2.10@d41d8cd9"
],
"devDependencies": [ "@opam/conf-libffi@opam:2.0.0@7c8981c5" ]
"@opam/ctypes@opam:0.18.0@1be5c5e5": {
"id": "@opam/ctypes@opam:0.18.0@1be5c5e5",
"name": "@opam/ctypes",
"version": "opam:0.18.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/5d/5d9ef3790fda7cd97a8cec08be4b5b61#md5:5d9ef3790fda7cd97a8cec08be4b5b61",
"archive:https://github.com/ocamllabs/ocaml-ctypes/archive/0.18.0.tar.gz#md5:5d9ef3790fda7cd97a8cec08be4b5b61"
],
"opam": {
"name": "ctypes",
"version": "0.18.0",
"path": "esy.lock/opam/ctypes.0.18.0"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__ctypes_opam__c__0.18.0_opam_override"
}
],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/integers@opam:0.4.0@f7acfaeb",
"@opam/ctypes-foreign@opam:0.4.0@6d218780",
"@opam/bigarray-compat@opam:1.0.0@3a87ad65",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/integers@opam:0.4.0@f7acfaeb",
"@opam/bigarray-compat@opam:1.0.0@3a87ad65"
]
},
"ocaml@4.11.1000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.1000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune-configurator@opam:2.8.2@c90ff40b",
"@opam/dune@opam:2.8.2@3d714e5f",
"ocaml@4.11.2000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c",
"ocaml@4.11.1000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune-configurator@opam:2.8.2@c90ff40b",
"@opam/dune@opam:2.8.2@3d714e5f"
"ocaml@4.11.2000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c"
"@opam/conf-pkg-config@opam:1.3@93481236",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": []
},
"@opam/conf-libsodium@github:EduardoRFS/esy-libsodium:libsodium.opam#caeedd7@d003f610": {
"id":
"@opam/conf-libsodium@github:EduardoRFS/esy-libsodium:libsodium.opam#caeedd7@d003f610",
"name": "@opam/conf-libsodium",
"version": "github:EduardoRFS/esy-libsodium:libsodium.opam#caeedd7",
"source": {
"type": "install",
"source": [
"github:EduardoRFS/esy-libsodium:libsodium.opam#caeedd7"
]
},
"overrides": [
{
"dependencies": {
"esy-libsodium": "github:EduardoRFS/esy-libsodium#caeedd7"
}
}
],
"dependencies": [
"esy-libsodium@archive:https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz#sha1:795b73e3f92a362fabee238a71735579bf46bb97@a5898027",
"@opam/conf-libopus@link:vendor/esy-libopus/conf-libopus.opam": {
"id": "@opam/conf-libopus@link:vendor/esy-libopus/conf-libopus.opam",
"name": "@opam/conf-libopus",
"version": "link:vendor/esy-libopus/conf-libopus.opam",
"source": {
"type": "link",
"path": "vendor/esy-libopus",
"manifest": "conf-libopus.opam"
},
"overrides": [
{ "dependencies": { "esy-libopus": "./vendor/esy-libopus" } }
],
"dependencies": [
"esy-libopus@archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b@24aa01e3",
"@opam/conf-pkg-config@opam:1.3@93481236",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": []
},
"@opam/conf-libffi@opam:2.0.0@7c8981c5": {
"id": "@opam/conf-libffi@opam:2.0.0@7c8981c5",
"name": "@opam/conf-libffi",
"version": "opam:2.0.0",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "conf-libffi",
"version": "2.0.0",
"path": "esy.lock/opam/conf-libffi.2.0.0"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__conf_libffi_opam__c__2.0.0_opam_override"
}
],
"dependencies": [
"esy-libffi@github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c@d41d8cd9",
"@opam/conf-pkg-config@opam:1.3@93481236",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": []
},
"devDependencies": [ "ocaml@4.11.1000@d41d8cd9" ]
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/charInfo_width@opam:1.1.0@4296bdfe": {
"id": "@opam/charInfo_width@opam:1.1.0@4296bdfe",
"name": "@opam/charInfo_width",
"version": "opam:1.1.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/a5/a539436d1da4aeb93711303f107bec7e#md5:a539436d1da4aeb93711303f107bec7e",
"archive:https://github.com/kandu/charInfo_width/archive/1.1.0.tar.gz#md5:a539436d1da4aeb93711303f107bec7e"
],
"opam": {
"name": "charInfo_width",
"version": "1.1.0",
"path": "esy.lock/opam/charInfo_width.1.1.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/camomile@opam:1.0.2@40411a6b",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/camomile@opam:1.0.2@40411a6b"
]
},
"@opam/camomile@opam:1.0.2@40411a6b": {
"id": "@opam/camomile@opam:1.0.2@40411a6b",
"name": "@opam/camomile",
"version": "opam:1.0.2",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/f0/f0a419b0affc36500f83b086ffaa36c545560cee5d57e84b729e8f851b3d1632#sha256:f0a419b0affc36500f83b086ffaa36c545560cee5d57e84b729e8f851b3d1632",
"archive:https://github.com/yoriyuki/Camomile/releases/download/1.0.2/camomile-1.0.2.tbz#sha256:f0a419b0affc36500f83b086ffaa36c545560cee5d57e84b729e8f851b3d1632"
],
"opam": {
"name": "camomile",
"version": "1.0.2",
"path": "esy.lock/opam/camomile.1.0.2"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
"ocaml@4.11.1000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.1000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"@opam/base-bigarray@opam:base@b03491b0": {
"id": "@opam/base-bigarray@opam:base@b03491b0",
"name": "@opam/base-bigarray",
"version": "opam:base",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "base-bigarray",
"version": "base",
"path": "esy.lock/opam/base-bigarray.base"
}
},
"overrides": [],
"dependencies": [ "@esy-ocaml/substs@0.0.1@d41d8cd9" ],
"devDependencies": []
},
"ocaml@4.11.1000@d41d8cd9", "@opam/sexplib0@opam:v0.14.0@ddeb6438",
"@opam/dune-configurator@opam:2.8.2@c90ff40b",
"@opam/dune@opam:2.8.2@3d714e5f", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.2000@d41d8cd9", "@opam/sexplib0@opam:v0.14.0@ddeb6438",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
"ocaml@4.11.1000@d41d8cd9", "@opam/sexplib0@opam:v0.14.0@ddeb6438",
"@opam/dune-configurator@opam:2.8.2@c90ff40b",
"@opam/dune@opam:2.8.2@3d714e5f"
"ocaml@4.11.2000@d41d8cd9", "@opam/sexplib0@opam:v0.14.0@ddeb6438",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c"
"devDependencies": [ "ocaml@4.11.1000@d41d8cd9" ]
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/angstrom-lwt-unix@opam:0.15.0@2ffc8053": {
"id": "@opam/angstrom-lwt-unix@opam:0.15.0@2ffc8053",
"name": "@opam/angstrom-lwt-unix",
"version": "opam:0.15.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/51/5104768c404ea92fd0a53a5b0f75cd50#md5:5104768c404ea92fd0a53a5b0f75cd50",
"archive:https://github.com/inhabitedtype/angstrom/archive/0.15.0.tar.gz#md5:5104768c404ea92fd0a53a5b0f75cd50"
],
"opam": {
"name": "angstrom-lwt-unix",
"version": "0.15.0",
"path": "esy.lock/opam/angstrom-lwt-unix.0.15.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/base-unix@opam:base@87d0b2eb",
"@opam/angstrom@opam:0.15.0@48ede9cb",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/lwt@opam:5.4.0@1ec6dbfd",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/base-unix@opam:base@87d0b2eb",
"@opam/angstrom@opam:0.15.0@48ede9cb"
]
"@opam/menhir@opam:20201216@1a09d886",
"@opam/fix@opam:20201120@5c318621", "@opam/dune@opam:2.8.2@3d714e5f"
"@opam/menhir@opam:20210310@50de9216",
"@opam/fix@opam:20201120@5c318621", "@opam/dune@opam:2.8.4@ee414d6c"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@esy-ocaml/libffi@3.2.10@d41d8cd9": {
"id": "@esy-ocaml/libffi@3.2.10@d41d8cd9",
"name": "@esy-ocaml/libffi",
"version": "3.2.10",
"source": {
"type": "install",
"source": [
"archive:https://registry.npmjs.org/@esy-ocaml/libffi/-/libffi-3.2.10.tgz#sha1:72697f135ee228b94294ec32f0d5b0fa313de403"
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"@discopotty/opus@link:vendor/opus/package.json": {
"id": "@discopotty/opus@link:vendor/opus/package.json",
"name": "@discopotty/opus",
"version": "link:vendor/opus/package.json",
"source": {
"type": "link",
"path": "vendor/opus",
"manifest": "package.json"
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ppx_cstubs@opam:0.6.1.1@706c3a9f",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/ctypes-foreign@opam:0.4.0@6d218780",
"@opam/ctypes@opam:0.18.0@1be5c5e5",
"@opam/conf-libopus@link:vendor/esy-libopus/conf-libopus.opam"
opam-version: "2.0"
maintainer: "Spiros Eliopoulos <spiros@inhabitedtype.com>"
authors: [ "Spiros Eliopoulos <spiros@inhabitedtype.com>" ]
license: "BSD-3-clause"
homepage: "https://github.com/inhabitedtype/angstrom"
bug-reports: "https://github.com/inhabitedtype/angstrom/issues"
dev-repo: "git+https://github.com/inhabitedtype/angstrom.git"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
depends: [
"ocaml" {>= "4.03.0"}
"dune" {>= "1.8"}
"angstrom"
"lwt"
"base-unix"
]
synopsis: "Lwt_unix support for Angstrom"
url {
src: "https://github.com/inhabitedtype/angstrom/archive/0.15.0.tar.gz"
checksum: "md5=5104768c404ea92fd0a53a5b0f75cd50"
}
opam-version: "2.0"
maintainer: "https://github.com/ocaml/opam-repository/issues"
description: """
Bigarray library distributed with the OCaml compiler
"""
opam-version: "2.0"
synopsis: "A Unicode library"
description: """
Camomile is a Unicode library for OCaml. Camomile provides Unicode character
type, UTF-8, UTF-16, UTF-32 strings, conversion to/from about 200 encodings,
collation and locale-sensitive case mappings, and more. The library is currently
designed for Unicode Standard 3.2."""
maintainer: ["yoriyuki.y@gmail.com"]
authors: ["Yoriyuki Yamagata"]
license: "LGPL-2.1-or-later with OCaml-LGPL-linking-exception"
homepage: "https://github.com/yoriyuki/Camomile"
doc: "https://yoriyuki.github.io/Camomile/"
bug-reports: "https://github.com/yoriyuki/Camomile/issues"
depends: [
"dune" {>= "1.11"}
"ocaml" {>= "4.02.3"}
]
dev-repo: "git+https://github.com/yoriyuki/Camomile.git"
build: [
["ocaml" "configure.ml" "--share" "%{share}%/camomile"]
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs
"@install"
"@doc" {with-doc}
]
]
url {
src:
"https://github.com/yoriyuki/Camomile/releases/download/1.0.2/camomile-1.0.2.tbz"
checksum: [
"sha256=f0a419b0affc36500f83b086ffaa36c545560cee5d57e84b729e8f851b3d1632"
"sha512=7586422e68779476206027c6ebbe19b677fbe459153221f7c952c7fae374c5c8232249cb76fdb1f482069707aa1580be827cd39693906142988268b7f0e7f6d0"
]
}
available: arch != "ppc64"
opam-version: "2.0"
maintainer: "zandoye@gmail.com"
authors: [ "ZAN DoYe" ]
homepage: "https://github.com/kandu/charinfo_width/"
bug-reports: "https://github.com/kandu/charinfo_width/issues"
license: "MIT"
dev-repo: "git://github.com/kandu/charinfo_width.git"
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test & (ocaml:version >= "4.04.0")}
]
depends: [
"ocaml" {>= "4.02.3"}
"result"
"camomile" {>= "1.0.0" & < "2.0~"}
"dune"
"ppx_expect" {with-test & < "v0.15"}
]
synopsis: "Determine column width for a character"
description: """
This module is implemented purely in OCaml and the width function follows the prototype of POSIX's wcwidth."""
url {
src:"https://github.com/kandu/charInfo_width/archive/1.1.0.tar.gz"
checksum: "md5=a539436d1da4aeb93711303f107bec7e"
}
opam-version: "2.0"
maintainer: "blue-prawn"
authors: ["Anthony Green"]
homepage: "http://sourceware.org/libffi/"
license: "MIT"
build: ["pkg-config" "libffi"]
depexts: [
["libffi"] {os = "macos" & os-distribution = "homebrew"}
["libffi"] {os = "macos" & os-distribution = "macports"}
["libffi-dev"] {os-distribution = "alpine"}
["libffi-dev"] {os-family = "debian"}
["libffi-devel"] {os-distribution = "centos"}
["libffi-devel"] {os-distribution = "fedora"}
["libffi-devel"] {os-distribution = "mageia"}
["libffi-devel"] {os-distribution = "ol"}
["libffi-devel"] {os-family = "suse"}
]
synopsis: "Virtual package relying on libffi system installation"
description: "This package can only install if libffi is installed on the system."
depends: ["conf-pkg-config" {build}]
bug-reports: "https://github.com/ocaml/opam-repository/issues"
flags: conf
opam-version: "2.0"
maintainer: "yallop@gmail.com"
homepage: "https://github.com/ocamllabs/ocaml-ctypes"
dev-repo: "git+http://github.com/ocamllabs/ocaml-ctypes.git"
bug-reports: "http://github.com/ocamllabs/ocaml-ctypes/issues"
depends: [
"conf-libffi" {>= "2.0.0"}
]
tags: ["org:ocamllabs" "org:mirage"]
post-messages: [
"This package requires libffi on your system" {failure}
]
synopsis: "Virtual package for enabling the ctypes.foreign subpackage."
description: """
`ctypes-foreign` is just a virtual OPAM package that determines
whether the foreign subpackage should built as part of ctypes.
In order to actually get the ctypes package, you should also:
opam install ctypes ctypes-foreign
You can verify the existence of the ocamlfind subpackage by:
ocamlfind list | grep ctypes
Which should output something like:
ctypes (version: 0.4.1)
ctypes.foreign (version: 0.4.1)
ctypes.foreign.base (version: 0.4.1)
ctypes.foreign.threaded (version: 0.4.1)
ctypes.foreign.unthreaded (version: 0.4.1)
ctypes.stubs (version: 0.4.1)
ctypes.top (version: 0.4.1)"""
authors: "yallop@gmail.com"
opam-version: "2.0"
maintainer: "yallop@gmail.com"
homepage: "https://github.com/ocamllabs/ocaml-ctypes"
doc: "http://ocamllabs.github.io/ocaml-ctypes"
dev-repo: "git+http://github.com/ocamllabs/ocaml-ctypes.git"
bug-reports: "http://github.com/ocamllabs/ocaml-ctypes/issues"
license: "MIT"
build: [
[make "XEN=%{mirage-xen:enable}%" "libffi.config"]
{ctypes-foreign:installed}
["touch" "libffi.config"] {!ctypes-foreign:installed}
[make "XEN=%{mirage-xen:enable}%" "ctypes-base" "ctypes-stubs"]
[make "XEN=%{mirage-xen:enable}%" "ctypes-foreign"]
{ctypes-foreign:installed}
[make "test"] {with-test}
]
install: [
[make "install" "XEN=%{mirage-xen:enable}%"]
]
depends: [
"ocaml" {>= "4.02.3"}
"integers" { >= "0.3.0" }
"ocamlfind" {build}
"lwt" {with-test & >= "3.2.0"}
"ctypes-foreign" {with-test}
"ounit" {with-test}
"conf-ncurses" {with-test}
"bigarray-compat"
]
depopts: [
"ctypes-foreign"
"mirage-xen"
]
tags: ["org:ocamllabs" "org:mirage"]
synopsis: "Combinators for binding to C libraries without writing any C"
description: """
ctypes is a library for binding to C libraries using pure OCaml. The primary
aim is to make writing C extensions as straightforward as possible.
The core of ctypes is a set of combinators for describing the structure of C
types -- numeric types, arrays, pointers, structs, unions and functions. You
can use these combinators to describe the types of the functions that you want
to call, then bind directly to those functions -- all without writing or
generating any C!
To install the optional `ctypes.foreign` interface (which uses `libffi` to
provide dynamic access to foreign libraries), you will need to also install
the `ctypes-foreign` optional dependency:
opam install ctypes ctypes-foreign
This will make the `ctypes.foreign` ocamlfind subpackage available."""
authors: "yallop@gmail.com"
url {
src: "https://github.com/ocamllabs/ocaml-ctypes/archive/0.18.0.tar.gz"
checksum: "md5=5d9ef3790fda7cd97a8cec08be4b5b61"
}
conflicts: [
"mirage-xen" {>= "6.0.0"}
]
"sha256=e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e"
"sha512=d3cca73f5a72440273f7b4e3934dfa7e89fcb64710f3c734d2583123f5d9f3e573f0ab96a4892b2f11313038da6b4e2c614951199ffef0a3f12669d729b25376"
"sha256=4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"sha512=efc1834c4add40138a101734665a1f462c19fe76d1cbb457b1fc20f95991118a50b24d485fb98d39046e41bec03885a8dc071bf8add51083ac9780bff9f6668a"
"sha256=e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e"
"sha512=d3cca73f5a72440273f7b4e3934dfa7e89fcb64710f3c734d2583123f5d9f3e573f0ab96a4892b2f11313038da6b4e2c614951199ffef0a3f12669d729b25376"
"sha256=4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"sha512=efc1834c4add40138a101734665a1f462c19fe76d1cbb457b1fc20f95991118a50b24d485fb98d39046e41bec03885a8dc071bf8add51083ac9780bff9f6668a"
"sha256=e2c4e8230f7c96236503fd75f22bdbc263639971bf104509e446855ded35ae1e"
"sha512=d3cca73f5a72440273f7b4e3934dfa7e89fcb64710f3c734d2583123f5d9f3e573f0ab96a4892b2f11313038da6b4e2c614951199ffef0a3f12669d729b25376"
"sha256=4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"sha512=efc1834c4add40138a101734665a1f462c19fe76d1cbb457b1fc20f95991118a50b24d485fb98d39046e41bec03885a8dc071bf8add51083ac9780bff9f6668a"
opam-version: "2.0"
maintainer: "Romain Calascibetta <romain.calascibetta@gmail.com>"
authors: "Romain Calascibetta <romain.calascibetta@gmail.com>"
homepage: "https://github.com/dinosaure/hxd"
bug-reports: "https://github.com/dinosaure/hxd/issues"
dev-repo: "git+https://github.com/dinosaure/hxd.git"
doc: "https://dinosaure.github.io/hxd/"
license: "MIT"
synopsis: "Hexdump in OCaml"
description: """Please, help me to debug ocaml-git
"""
build: [
[ "dune" "build" "-p" name "-j" jobs ]
[ "dune" "runtest" "-p" name "-j" jobs ] {with-test}
]
depends: [
"ocaml" {>= "4.06.0"}
"dune" {>= "2.7"}
"dune-configurator" {>= "2.7"}
"cmdliner"
]
depopts: [
"lwt"
]
x-commit-hash: "cee4cc97391634d4c4cb15250946dfc5782e335e"
url {
src:
"https://github.com/dinosaure/hxd/releases/download/v0.3.1/hxd-v0.3.1.tbz"
checksum: [
"sha256=1c226c91e17cd329dec0c287bfd20f36302aa533069ff9c6ced32721f96b29bc"
"sha512=93ff909eb519f750794684dcb050bdf51d271652dcea5501654e63b6ac17b79a85981f984a2e1a6db963240de594f21dde4dc541ef8e5873b906fa50d4ef803b"
]
}
opam-version: "2.0"
maintainer: "yallop@gmail.com"
authors: ["Jeremy Yallop"
"Demi Obenour"
"Stephane Glondu"
"Andreas Hauptmann"]
homepage: "https://github.com/ocamllabs/ocaml-integers"
bug-reports: "https://github.com/ocamllabs/ocaml-integers/issues"
dev-repo: "git+https://github.com/ocamllabs/ocaml-integers.git"
license: "MIT"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
depends: [
"ocaml" {>= "4.02"}
"dune"
]
doc: "http://ocamllabs.github.io/ocaml-integers/api.docdir/"
synopsis: "Various signed and unsigned integer types for OCaml"
url {
src: "https://github.com/ocamllabs/ocaml-integers/archive/0.4.0.tar.gz"
checksum: "md5=c1492352e6525048790508c57aad93c3"
}
opam-version: "2.0"
maintainer: "jeremie@dimino.org"
authors: ["Jérémie Dimino"]
homepage: "https://github.com/ocaml-community/lambda-term"
bug-reports: "https://github.com/ocaml-community/lambda-term/issues"
dev-repo: "git://github.com/ocaml-community/lambda-term.git"
license: "BSD-3-Clause"
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
depends: [
"ocaml" {>= "4.02.3"}
"lwt" {>= "4.0.0"}
"lwt_log"
"react"
"zed" {>= "3.1.0" & < "4.0"}
"camomile" {>= "1.0.1"}
"lwt_react"
"mew_vi" {>= "0.5.0" & < "0.6.0"}
"dune" {>= "1.1.0"}
]
synopsis: "Terminal manipulation library for OCaml"
description: """
Lambda-term is a cross-platform library for manipulating the terminal. It
provides an abstraction for keys, mouse events, colors, as well as a set of
widgets to write curses-like applications. The main objective of lambda-term is
to provide a higher level functional interface to terminal manipulation than,
for example, ncurses, by providing a native OCaml interface instead of bindings
to a C library. Lambda-term integrates with zed to provide text edition
facilities in console applications."""
url {
src: "https://github.com/ocaml-community/lambda-term/archive/3.1.0.tar.gz"
checksum: "md5=78180c04ecfc8060b23d7d0014f24196"
}
opam-version: "2.0"
synopsis: "Lwt logging library (deprecated)"
version: "1.1.1"
license: "LGPL-2.0-or-later"
homepage: "https://github.com/ocsigen/lwt_log"
doc: "https://github.com/ocsigen/lwt_log/blob/master/src/core/lwt_log_core.mli"
bug-reports: "https://github.com/ocsigen/lwt_log/issues"
authors: [
"Shawn Wagner"
"Jérémie Dimino"
]
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
dev-repo: "git+https://github.com/ocsigen/lwt_log.git"
depends: [
"dune" {>= "1.0"}
"lwt" {>= "4.0.0"}
]
build: [
["dune" "build" "-p" name "-j" jobs]
]
url {
src: "https://github.com/aantron/lwt_log/archive/1.1.1.tar.gz"
checksum: "md5=02e93be62288037870ae5b1ce099fe59"
}
opam-version: "2.0"
synopsis: "Helpers for using React with Lwt"
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
authors: "Jérémie Dimino"
license: "MIT"
homepage: "https://github.com/ocsigen/lwt"
doc: "https://ocsigen.org/lwt/dev/api/Lwt_react"
bug-reports: "https://github.com/ocsigen/lwt/issues"
depends: [
"dune" {>= "1.8.0"}
"lwt" {>= "3.0.0"}
"ocaml"
"react" {>= "1.0.0"}
]
build: ["dune" "build" "-p" name "-j" jobs]
dev-repo: "git+https://github.com/ocsigen/lwt.git"
url {
src: "https://github.com/ocsigen/lwt/archive/5.4.0.zip"
checksum: [
"md5=fc4721bdb1a01225b96e3a2debde95fa"
"sha512=e427f08223b77f9af696c9e6f90ff68e27e02e446910ef90d3da542e7b00bf23dd191ac77c1871288faa2289f8d28fc2f44efc3d3fe9165fe1c7a6be88ee49ff"
]
}
"md5=f27f8f5dedd316eff4c02d9130fced49"
"sha512=50f86fb2f55184f43c4be9c572ada4feb2208eb350ef64b2651351934a1b48a0b7e98c8c752c3c22e95676c5a0f38b0e638b3f845e53ecff1740dad95b50918c"
"md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f"
"md5=f27f8f5dedd316eff4c02d9130fced49"
"sha512=50f86fb2f55184f43c4be9c572ada4feb2208eb350ef64b2651351934a1b48a0b7e98c8c752c3c22e95676c5a0f38b0e638b3f845e53ecff1740dad95b50918c"
"md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f"
"md5=f27f8f5dedd316eff4c02d9130fced49"
"sha512=50f86fb2f55184f43c4be9c572ada4feb2208eb350ef64b2651351934a1b48a0b7e98c8c752c3c22e95676c5a0f38b0e638b3f845e53ecff1740dad95b50918c"
"md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f"
opam-version: "2.0"
maintainer: "zandoye@gmail.com"
authors: [ "ZAN DoYe" ]
homepage: "https://github.com/kandu/mew"
bug-reports: "https://github.com/kandu/mew/issues"
license: "MIT"
dev-repo: "git+https://github.com/kandu/mew.git"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.02.3"}
"result"
"trie"
"dune" {>= "1.1.0"}
]
synopsis: "Modal editing witch"
description: """
This is the core module of mew, a general modal editing engine generator."""
url {
src: "https://github.com/kandu/mew/archive/0.1.0.tar.gz"
checksum: "md5=2298149d1415cd804ab4e01f01ea10a0"
}
opam-version: "2.0"
maintainer: "zandoye@gmail.com"
authors: [ "ZAN DoYe" ]
homepage: "https://github.com/kandu/mew_vi"
bug-reports: "https://github.com/kandu/mew_vi/issues"
license: "MIT"
dev-repo: "git+https://github.com/kandu/mew_vi.git"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.02.3"}
"mew" {>= "0.1.0" & < "0.2"}
"react"
"dune" {>= "1.1.0"}
]
synopsis: "Modal editing witch, VI interpreter"
description: """
A vi-like modal editing engine generator."""
url {
src: "https://github.com/kandu/mew_vi/archive/0.5.0.tar.gz"
checksum: "md5=341e9a9a20383641015bf503952906bc"
}
opam-version: "2.0"
synopsis:
"The legacy Num library for arbitrary-precision integer and rational arithmetic"
maintainer: "Xavier Leroy <xavier.leroy@inria.fr>"
authors: ["Valérie Ménissier-Morain" "Pierre Weis" "Xavier Leroy"]
license: "LGPL-2.1-only with OCaml-LGPL-linking-exception"
homepage: "https://github.com/ocaml/num/"
bug-reports: "https://github.com/ocaml/num/issues"
depends: [
"ocaml" {>= "4.06.0"}
"ocamlfind" {build & >= "1.7.3"}
]
conflicts: ["base-num"]
build: make
install: [
make
"install" {!ocaml:preinstalled}
"findlib-install" {ocaml:preinstalled}
]
dev-repo: "git+https://github.com/ocaml/num.git"
url {
src: "https://github.com/ocaml/num/archive/v1.4.tar.gz"
checksum: [
"md5=cda2b727e116a0b6a9c03902cc4b2415"
"sha512=0cc9be8ad95704bb683b4bf6698bada1ee9a40dc05924b72adc7b969685c33eeb68ccf174cc09f6a228c48c18fe94af06f28bebc086a24973a066da620db8e6f"
]
}
"sha256=24b2f324ea91cff98bb8790a6746ccce3173bac5f57cb457156e5c50a0467397"
"sha512=a1936198e6e563ed703c8cd9d481394660fb25e9e700ea481e5326536c2734d9356c99750ae3ef8a55614776cc040c05cbcf2e03f609ab1f78c34aab0c5de830"
"sha256=ac7ba16a09d8f72212742f3936980fbfaebb698c7bbf625182af7d6b2c3cde5f"
"sha512=6e11823531f1f70b5d4b90ed9f2fcc22cbf83924a7a0ef40eebc4b80598db6acdaca97f1d379e01860513d5dda492f5bc4d944f0c1dd7df491b2f36a0f729bb5"
opam-version: "2.0"
maintainer: "andreashauptmann@t-online.de"
authors: [ "andreashauptmann@t-online.de" ]
license: "LGPL-2.1-or-later with OCaml-LGPL-linking-exception"
homepage: "https://fdopen.github.io/ppx_cstubs/"
dev-repo: "git+https://github.com/fdopen/ppx_cstubs.git"
doc: "https://fdopen.github.io/ppx_cstubs/"
bug-reports: "https://github.com/fdopen/ppx_cstubs/issues"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"bigarray-compat"
"ctypes" {>= "0.13.0" & < "0.19"}
"integers"
"num"
"result"
"containers" {>= "2.2"}
"cppo" {build & >= "1.3"}
"ocaml" {>= "4.04.2" & < "4.13.0"}
"ppxlib" {>= "0.22.0"}
"ocamlfind" {>= "1.7.2"} # not only a build dependency, it depends on findlib.top
"dune" {>= "1.6"}
"re" {>= "1.7.2"}
]
synopsis: """
Preprocessor for easier stub generation with ctypes
"""
description: """
ppx_cstubs is a ppx-based preprocessor for stub generation with
ctypes. ppx_cstubs creates two files from a single ml file: a file
with c stub code and an OCaml file with all additional boilerplate
code.
"""
url {
src: "https://github.com/fdopen/ppx_cstubs/archive/0.6.1.1.tar.gz"
checksum: [
"md5=33e520e369da5630c697318f6f4ed26d"
"sha512=77f28fd93ba476ccad089029fb7c7254a4525ea2d61f4d0a74c69b8c771e2657929c16cfa334671ccead1c02743804fc3db7726fd3e47772f50dc4a16270435c"
]
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
homepage: "http://erratique.ch/software/react"
authors: ["Daniel Bünzli <daniel.buenzl i@erratique.ch>"]
doc: "http://erratique.ch/software/react/doc/React"
dev-repo: "git+http://erratique.ch/repos/react.git"
bug-reports: "https://github.com/dbuenzli/react/issues"
tags: [ "reactive" "declarative" "signal" "event" "frp" "org:erratique" ]
license: "ISC"
depends: [
"ocaml" {>= "4.01.0"}
"ocamlfind" {build}
"ocamlbuild" {build}
"topkg" {build & >= "0.9.0"}
]
build:
[[ "ocaml" "pkg/pkg.ml" "build"
"--dev-pkg" "%{pinned}%" ]]
synopsis: "Declarative events and signals for OCaml"
description: """
Release %%VERSION%%
React is an OCaml module for functional reactive programming (FRP). It
provides support to program with time varying values : declarative
events and signals. React doesn't define any primitive event or
signal, it lets the client chooses the concrete timeline.
React is made of a single, independent, module and distributed under
the ISC license."""
url {
src: "http://erratique.ch/software/react/releases/react-1.2.1.tbz"
checksum: "md5=ce1454438ce4e9d2931248d3abba1fcc"
}
opam-version: "2.0"
maintainer: ["Markus W. Weissmann <markus.weissmann@in.tum.de>"]
authors: [
"Andre Nathan <andre@digirati.com.br>"
"Jeff Shaw <shawjef3@msu.edu>"
"Markus W. Weissmann <markus.weissmann@in.tum.de>"
"Florian Pichlmeier <florian.pichlmeier@mytum.de>"
]
bug-reports: "https://github.com/andrenth/ocaml-stdint/issues"
homepage: "https://github.com/andrenth/ocaml-stdint"
doc: "https://andrenth.github.io/ocaml-stdint/"
license: "MIT"
dev-repo: "git+https://github.com/andrenth/ocaml-stdint.git"
synopsis: "Signed and unsigned integer types having specified widths"
description: """
The stdint library provides signed and unsigned integer types of various fixed
widths: 8, 16, 24, 32, 40, 48, 56, 64 and 128 bit.
This interface is similar to Int32 and Int64 from the base library but provides
more functions and constants like arithmetic and bit-wise operations, constants
like maximum and minimum values, infix operators conversion to and from every
other integer type (including int, float and nativeint), parsing from and
conversion to readable strings (binary, octal, decimal, hexademical), conversion
to and from buffers in both big endian and little endian byte order."""
depends: [
"ocaml" {>= "4.03"}
"odoc" {with-doc}
"dune" {>= "1.10"}
]
build: [
["dune" "subst"] {pinned}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@doc" {with-doc}
]
]
x-commit-hash: "f3eb95c3807249e1fb8ca635bdaa1ef98f7249da"
url {
src:
"https://github.com/andrenth/ocaml-stdint/releases/download/0.7.0/stdint-0.7.0.tbz"
checksum: [
"sha256=4fcc66aef58e2b96e7af3bbca9d910aa239e045ba5fb2400aaef67d0041252dc"
"sha512=9b05b6cf691320b718dd2118b1e3f96a2997e42e6c99a34b470b060c82fc16c50d57c6ee392d1b62bdb8df73094657eea56050da3e74745a4afb0f150a60a584"
]
}
opam-version: "2.0"
maintainer: "zandoye@gmail.com"
authors: [ "ZAN DoYe" ]
homepage: "https://github.com/kandu/trie/"
bug-reports: "https://github.com/kandu/trie/issues"
license: "MIT"
dev-repo: "git://github.com/kandu/trie.git"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.02"}
"dune" {>= "1.0"}
]
synopsis: "Strict impure trie tree"
url {
src: "https://github.com/kandu/trie/archive/1.0.0.tar.gz"
checksum: "md5=84519b5f8bd92490bfc68a52f706ba14"
}
opam-version: "2.0"
maintainer: "jeremie@dimino.org"
authors: "Jérémie Dimino"
license: "BSD3"
homepage: "https://github.com/ocaml-community/utop"
bug-reports: "https://github.com/ocaml-community/utop/issues"
doc: "https://ocaml-community.github.io/utop/"
depends: [
"ocaml" {>= "4.03.0" & < "4.13"}
"base-unix"
"base-threads"
"ocamlfind" {>= "1.7.2"}
"lambda-term" {>= "3.1.0" & < "4.0"}
"lwt"
"lwt_react"
"camomile"
"react" {>= "1.0.0"}
"cppo" {build & >= "1.1.2"}
"dune" {>= "1.0"}
]
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
dev-repo: "git+https://github.com/ocaml-community/utop.git"
synopsis: "Universal toplevel for OCaml"
description: """
utop is an improved toplevel (i.e., Read-Eval-Print Loop or REPL) for
OCaml. It can run in a terminal or in Emacs. It supports line
edition, history, real-time and context sensitive completion, colors,
and more. It integrates with the Tuareg mode in Emacs.
"""
x-commit-hash: "a5ff52bbf608e1112b5c0d41a36e3267f39f4084"
url {
src:
"https://github.com/ocaml-community/utop/releases/download/2.7.0/utop-2.7.0.tbz"
checksum: [
"sha256=e068ac53df267c3cc0f2f69bbc204404f0362cc4e6472a1fc547e326a63c3fdd"
"sha512=fc6237ff3e80c509a698872e5571b58e914d24c308a634e45972b7f104d960f17eba507535f56fcec972ea8c71143a8036cd122618e63cdf77fb6034297924df"
]
}
opam-version: "2.0"
maintainer: "opam-devel@lists.ocaml.org"
authors: ["Jérémie Dimino"]
homepage: "https://github.com/ocaml-community/zed"
bug-reports: "https://github.com/ocaml-community/zed/issues"
dev-repo: "git://github.com/ocaml-community/zed.git"
license: "BSD-3-Clause"
depends: [
"ocaml" {>= "4.02.3"}
"dune" {>= "1.1.0"}
"base-bytes"
"camomile" {>= "1.0.1"}
"react"
"charInfo_width" {>= "1.1.0" & < "2.0~"}
]
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
synopsis: "Abstract engine for text edition in OCaml"
description: """
Zed is an abstract engine for text edition. It can be used to write text
editors, edition widgets, readlines, ... Zed uses Camomile to fully support the
Unicode specification, and implements an UTF-8 encoded string type with
validation, and a rope datastructure to achieve efficient operations on large
Unicode buffers. Zed also features a regular expression search on ropes. To
support efficient text edition capabilities, Zed provides macro recording and
cursor management facilities."""
url {
src: "https://github.com/ocaml-community/zed/archive/3.1.0.tar.gz"
checksum: "md5=51e8676ba972e5ad727633c161e404b1"
}
name: esy
on: [push, pull_request]
jobs:
native:
name: Build for Native
strategy:
matrix:
system: [ubuntu, macos]
runs-on: ${{ matrix.system }}-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- uses: actions/setup-node@v2-beta
with:
node-version: 14
- name: Install esy
run: npm install -g esy
- name: Create esy wrapper
run: |
echo '{
"name": "build-sodium",
"dependencies": {
"@opam/conf-libsodium": "*",
"@opam/sodium": "*"
},
"resolutions": {
"@opam/conf-libsodium": {
"source": "./libsodium.opam",
"override": {
"dependencies": {
"esy-libsodium": "github:EduardoRFS/esy-libsodium#'"${GITHUB_SHA}"'"
}
}
},
"@opam/sodium": "github:EduardoRFS/ocaml-sodium:sodium.json#d3f147594c0bd374c88d07d0274230770c40cc7d"
}
}' > build.json
- name: Generate esy lock
run: esy @build solve
- uses: esy/github-action@master
with:
manifest: ./build.json
cache-key: ${{ hashFiles('esy.lock/index.json') }}
_esy
build.esy.lock
opam-version: "2.0"
maintainer: "Grégoire Henry <gregoire.henry@ocamlpro.com>"
authors: [
"Adam Langley"
"Alex Biryukov"
"Bo-Yin Yang"
"Christian Winnerlein"
"Colin Percival"
"Daniel Dinu"
"Daniel J. Bernstein"
"Dmitry Khovratovich"
"Jean-Philippe Aumasson"
"Niels Duif"
"Peter Schwabe"
"Samuel Neves"
"Tanja Lange"
"Zooko Wilcox-O'Hearn"
]
homepage: "https://download.libsodium.org/doc/"
license: "ISC"
build: [["pkg-config" "libsodium"]]
depends: ["conf-pkg-config" {build}]
depexts: [
["libsodium-dev"] {os-family = "debian"}
["security/libsodium"] {os = "freebsd"}
["libsodium"] {os-distribution = "homebrew" & os = "macos"}
["libsodium-dev"] {os-distribution = "alpine"}
]
synopsis: "Virtual package relying on a libsodium system installation"
description:
"This package can only install if the libsodium is installed on the system."
bug-reports: "https://github.com/ocaml/opam-repository/issues"
flags: conf
{
"version": "1.0.18123",
"source": "https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz#795b73e3f92a362fabee238a71735579bf46bb97",
"override": {
"buildsInSource": true,
"build": [
[
"./configure",
"--disable-debug",
"--disable-dependency-tracking",
"--prefix=$cur__install"
],
[
"make",
"-j4"
]
],
"install": "make install",
"exportedEnv": {
"PKG_CONFIG_PATH": {
"val": "#{self.lib / 'pkgconfig' }:$PKG_CONFIG_PATH",
"scope": "global"
},
"SODIUM_INCLUDE_PATH": {
"val": "#{self.install / 'include'}",
"scope": "global"
},
"SODIUM_LIB_PATH": {
"val": "#{self.lib}",
"scope": "global"
},
"LD_LIBRARY_PATH": {
"val": "#{self.lib : $LD_LIBRARY_PATH}",
"scope": "global"
}
}
}
}
{
"source": "github:dsheets/ocaml-sodium:opam#1f064fa90cd02c44e2dcc0708d4ba3a256a9c1f2",
"override": {
"build": [
["make", "CFLAGS=\"-I$SODIUM_INCLUDE_PATH -L$SODIUM_LIB_PATH\"", "-j4"]
],
"install": "make PREFIX=$cur__install install",
"dependencies": {
"@opam/conf-libsodium": "*"
}
}
}
{
"build": "true",
"dependencies": {
"esy-libffi": "esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c"
}
}
{
"dependencies": {
"@esy-ocaml/libffi": "3.2.10"
}
}
{
"exportedEnv": {
"CAML_LD_LIBRARY_PATH": {
"val": "#{self.lib / 'ctypes' : $CAML_LD_LIBRARY_PATH}",
"scope": "global"
}
}
}
diff --git a/src/Makefile b/src/Makefile
index 8ad0e2c..d41d63c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,16 +1,16 @@
-OCAMLC=ocamlc
-OCAMLOPT=ocamlopt
-OCAMLDEP=ocamldep
-OCAMLMKLIB=ocamlmklib
-OCAMLFIND=ocamlfind
+OCAMLC=$(shell which ocamlc)
+OCAMLOPT=$(shell which ocamlopt)
+OCAMLDEP=$(shell which ocamldep)
+OCAMLMKLIB=$(shell which ocamlmklib)
+OCAMLFIND=$(shell which ocamlfind)
INSTALL_DATA=install -m 644
INSTALL_DLL=install
INSTALL_DIR=install -d
STDLIBDIR=$(shell $(OCAMLC) -where)
DESTDIR ?=
-include $(STDLIBDIR)/Makefile.config
+include $(STDLIBDIR)/Makefile.config
ifeq "$(filter i386 amd64 arm64 power,$(ARCH))" ""
# Unsupported architecture
BNG_ARCH=generic
@@ -86,14 +86,14 @@ endif
VERSION=$(shell sed -ne 's/^ *version *: *"\([^"]*\)".*$$/\1/p' ../num.opam)
install:
- $(INSTALL_DIR) $(DESTDIR)$(STDLIBDIR)
+ $(INSTALL_DIR) $(LIBDIR)
sed -e 's/%%VERSION%%/$(VERSION)/g' META.in > META
$(OCAMLFIND) install num META
rm -f META
- $(INSTALL_DATA) $(TOINSTALL) $(DESTDIR)$(STDLIBDIR)
+ $(INSTALL_DATA) $(TOINSTALL) $(LIBDIR)
ifeq "$(SUPPORTS_SHARED_LIBRARIES)" "true"
- $(INSTALL_DIR) $(DESTDIR)$(STDLIBDIR)/stublibs
- $(INSTALL_DLL) $(TOINSTALL_STUBS) $(DESTDIR)$(STDLIBDIR)/stublibs
+ $(INSTALL_DIR) $(LIBDIR)/stublibs
+ $(INSTALL_DLL) $(TOINSTALL_STUBS) $(LIBDIR)/stublibs
endif
findlib-install:
@@ -105,9 +105,9 @@ findlib-uninstall:
$(OCAMLFIND) remove num
uninstall: findlib-uninstall
- cd $(DESTDIR)$(STDLIBDIR) && rm -f $(TOINSTALL)
+ cd $(LIBDIR) && rm -f $(TOINSTALL)
ifeq "$(SUPPORTS_SHARED_LIBRARIES)" "true"
- cd $(DESTDIR)$(STDLIBDIR)/stublibs && rm -f $(TOINSTALL_STUBS)
+ cd $(LIBDIR)/stublibs && rm -f $(TOINSTALL_STUBS)
endif
clean:
{
"buildsInSource": true,
"build": [
[
"make"
]
],
"install": [
[
"make",
"LIBDIR=#{self.install / 'lib'}",
"findlib-install"
]
],
"exportedEnv": {
"CAML_LD_LIBRARY_PATH": {
"val": "#{self.install / 'lib' / 'num' : $CAML_LD_LIBRARY_PATH}",
"scope": "global"
}
},
"dependencies": {
"ocaml": "*",
"@opam/ocamlfind": "*"
}
}
"nix-wrangle-pkg": {
"flake": false,
"locked": {
"lastModified": 1606447617,
"narHash": "sha256-yHejSB3cZbHyBgMiiu0BweKqimN0KVosBmjSY9mjT0E=",
"owner": "timbertson",
"repo": "nix-wrangle",
"rev": "25625d48f91785715dc62d7d90e44777839fa03d",
"type": "github"
},
"original": {
"owner": "timbertson",
"repo": "nix-wrangle",
"type": "github"
}
},
"type": "github"
}
},
"opam2nix-pkg": {
"flake": false,
"locked": {
"lastModified": 1614045149,
"narHash": "sha256-4SJSfK6vRGvQvTFfy3Jgg8u2rGHsya0ee0ziCIvhxew=",
"owner": "timbertson",
"repo": "opam2nix",
"rev": "d1d4cb15131bf45c9402aeff7df05dc78a92add7",
"type": "github"
},
"original": {
"owner": "timbertson",
"repo": "opam2nix",
open Globals
module L = (val Relog.logger ~namespace:__MODULE__ ())
open Lwt.Infix
let _SAMPLE_RATE = 48000
let _CHANNELS = 2
let _FRAME_LEN = 20
let _FRAME_SIZE = _SAMPLE_RATE / 1000 * _FRAME_LEN
(** Maximum packet size for a voice packet.
Set a safe amount below the Ethernet MTU to avoid fragmentation/rejection. *)
let _VOICE_PACKET_MAX = 1460
(* https://tools.ietf.org/html/rfc7587#section-4.2 *)
let ts_incr = Uint32.of_int @@ (48000 / 1000 * _FRAME_LEN)
let silence_frame =
[ '\xf8'; '\xff'; '\xfe' ] |> String.of_list
|> Bigstringaf.of_string ~off:0 ~len:3
let silence_stream = Lwt_stream.from_direct (fun () -> Some silence_frame)
let n_silence_pipe ?(n = 10) () =
Lwt_pipe.of_list (List.init n (fun _ -> silence_frame))
let of_pipe p =
let out = Lwt_pipe.create () in
let rec poll' () =
Lwt_pipe.read p >>= function
| None -> Lwt.return_unit
| Some data -> (
Lwt_pipe.write out data >>= function
| true -> poll' ()
| false -> Lwt.return_unit)
in
let fwd = poll' () in
Lwt_pipe.keep out fwd;
Lwt.on_termination fwd (fun () -> Lwt_pipe.close_nonblock out);
out
module Gen = struct
(** Fractional part of a float. *)
let fracf x = if x <. 1. then x else if x <. 2. then x -. 1. else fst (modf x)
let s16 =
let r = Int16.(max_int |> to_float) in
fun f -> Int.of_float (Float.(min 1. (max (-1.) f)) *. r)
let sine ?(freq = 440) ?(phase = 0.) ?(samplerate = 48000) ?(framelen = 20)
?(channels = 2) duration =
let phase = ref phase in
let framesize = samplerate / 1000 * framelen in
let volume = 0.5 in
let omega = float freq /. float samplerate in
let gen =
let buf =
Bigarray.(Array1.create float32 c_layout (framesize * channels))
in
fun () ->
for i = 0 to framesize - 1 do
let sample = volume *. sin ((float i *. omega) +. !phase) in
(* let sample = s16 sample in *)
for c = 0 to channels - 1 do
buf.{i + c} <- sample
done
done;
phase :=
mod_float (!phase +. (float framesize *. omega)) (2. *. Float.pi);
buf
in
let p = Lwt_pipe.create () in
let rec write = function
| 0 -> Lwt.return_unit
| n ->
Lwt_pipe.write p (gen ()) >>= fun ok ->
if ok then write (n - 1) else Lwt.return_unit
in
let nframes = Int.of_float (duration *. 1e3) / framelen in
let fut = write nframes in
Lwt_pipe.keep p fut;
Lwt.on_termination fut (fun () -> Lwt_pipe.close_nonblock p);
p
end
module Ffmpeg = struct
module L = (val Relog.clone (module L) ~namespace:"Ffmpeg")
module Parser = struct
let frame ~sample_p ~channels ~size ~kind =
let buf =
Bigarray.Array1.create kind Bigarray.c_layout (channels * size)
in
let p =
let open Angstrom in
let sample = count channels sample_p in
let rec samples ?(i = 0) () =
end_of_input >>| (fun () -> `eof) <|> (sample >>| fun s -> `sample s)
>>= function
| `eof -> return ()
| `sample chans ->
List.iteri (fun ci c -> buf.{i + ci} <- c) chans;
samples ~i:(i + channels) ()
in
samples () >>| fun () -> buf
in
fun buf ->
Angstrom.parse_bigstring ~consume:Angstrom.Consume.All p buf |> function
| Ok frame -> frame
| Error str -> failwith @@ "error parsing raw audio frame " ^ str
let s16le ?(channels = 2) ?(frame_size = 48000) =
frame ~sample_p:Angstrom.LE.any_int16 ~channels ~size:frame_size
~kind:Bigarray.int16_signed
let s16be ?(channels = 2) ?(frame_size = 48000) =
frame ~sample_p:Angstrom.BE.any_int16 ~channels ~size:frame_size
~kind:Bigarray.int16_signed
let f32le ?(channels = 2) ?(frame_size = 48000) =
frame ~sample_p:Angstrom.LE.any_float ~channels ~size:frame_size
~kind:Bigarray.float32
let f32be ?(channels = 2) ?(frame_size = 48000) =
frame ~sample_p:Angstrom.BE.any_float ~channels ~size:frame_size
~kind:Bigarray.float32
let f64le ?(channels = 2) ?(frame_size = 48000) =
frame ~sample_p:Angstrom.LE.any_double ~channels ~size:frame_size
~kind:Bigarray.float64
let f64be ?(channels = 2) ?(frame_size = 48000) =
frame ~sample_p:Angstrom.BE.any_double ~channels ~size:frame_size
~kind:Bigarray.float64
end
let pcm_args =
[ "-analyzeduration"; "0"; "-f"; "s16le"; "-ar"; "48000"; "-ac"; "2" ]
(* let ogg_args =
[ "-analyzeduration"; "0"; "-f"; "s16le"; "-ar"; "48000"; "-ac"; "2" ] *)
let stdout_args = [ "-" ]
let of_file filename =
let cmd = "ffmpeg" in
let args = List.concat [ [ "-i"; filename ]; pcm_args; stdout_args ] in
let p = Lwt_pipe.create () in
let p_p, u_p = Lwt.wait () in
let spawn () =
let cmd_str = cmd :: args |> List.to_string ~sep:" " Fun.id in
L.info (fun m -> m "running cmd: %s" cmd_str);
Lwt_process.with_process_full
("", Array.of_list @@ cmd :: args)
(fun proc ->
let raw = proc#stdout in
let logs () = Lwt_io.read proc#stderr in
L.info (fun m -> m "ffmpeg running with pid=%d" proc#pid);
let buf = Bigstringaf.create (_FRAME_SIZE * _CHANNELS * 2) in
let buf_len = Bigstringaf.length buf in
let parse_frame =
let parser =
Parser.s16le ~channels:_CHANNELS ~frame_size:_FRAME_SIZE
in
fun () -> parser buf
in
let rec poll' () =
L.trace (fun m -> m "polling");
Lwt_io.read_into_exactly_bigstring raw buf 0 buf_len
|> Lwt_result.catch
>>= function
| Ok () ->
L.trace (fun m -> m "parsing frame");
let frame = parse_frame () in
if Lwt.is_sleeping p_p then Lwt.wakeup_later u_p (Ok p);
Lwt_pipe.write p frame >>= fun ok ->
if ok then poll' () else proc#close >|= ignore
| Error End_of_file -> Lwt.return_unit
| Error exn -> Lwt.fail exn
in
let open Lwt.Syntax in
let* status = poll' () >>= fun () -> proc#status in
let+ res =
match status with
| Unix.WEXITED 0 ->
if Lwt.is_sleeping p_p then
Lwt_result.fail (`Msg "0 byte stream?")
else Lwt_result.return ()
| WEXITED n ->
L.error (fun m ->
m "got non 0 status code for ffmpeg (status=%d)" n);
let+ logs = logs () in
L.error (fun m -> m "logs:@.%s" logs);
Error
(`Msg
(Printf.sprintf
"got non 0 status code for ffmpeg (status=%d)\n%s" n logs))
| WSIGNALED n | WSTOPPED n ->
L.warn (fun m -> m "ffmpeg process was closed with code=%d" n);
Lwt_result.return ()
in
match (Lwt.is_sleeping p_p, res) with
| true, (Error _ as e) -> Lwt.wakeup_later u_p e
| true, Ok () -> ()
| false, _ -> ())
in
let k = spawn () in
Lwt_pipe.keep p k;
Lwt.on_termination k (fun () -> Lwt_pipe.close_nonblock p);
p_p |> Lwt_result.map of_pipe
end
let msg = { content; nounce = Websocket.gen_nonce 20; tts = false } in
let uri = Format.sprintf "/channels/%s/messages" channel_id in
let msg = { content; nonce = Websocket.gen_nonce 20; tts = false } in
let uri =
Format.sprintf "/channels/%s/messages"
(Models.Snowflake.to_string channel_id)
in
Lwt.async (fun () ->
Http.post ~body:ser uri http
|> Lwt.map (function
| Ok _ -> ()
| Error _ -> L.error (fun m -> m "error sending message")))
Http.post ~body:ser uri http
|> Lwt.map (function
| Ok _ -> ()
| Error _ -> L.error (fun m -> m "error sending message"))
let join_voice ~guild_id ~channel_id { gw; _ } =
Gateway.join_voice ~guild_id ~channel_id gw
|> Lwt.map (function
| Ok _ -> ()
| Error e ->
L.error (fun m ->
m "couldn't join voice channel '%Ld' on guild '%Ld: %s"
channel_id guild_id (Error.to_string e)))
let catch_lwt p = Lwt_result.(catch p |> map_err (fun exn -> `Exn exn))
let tap ~f r = function
| Ok o -> Ok o
| Error e ->
f e;
r
let tap_lwt ~f r = function
| Ok o -> Lwt.return (Ok o)
| Error e -> Lwt.bind (f e) (fun () -> r)
}
[@@deriving yojson] [@@yojson.allow_extra_fields]
end
module VoiceState = struct
type t = {
guild_id : Models.Snowflake.t option; [@yojson.option]
channel_id : Models.Snowflake.t option;
user_id : Models.Snowflake.t;
(* member: guild option; [@yojson.option]; *)
session_id : string;
deaf : bool;
mute : bool;
self_deaf : bool;
self_mute : bool;
self_stream : bool option; [@yojson.option]
self_video : bool;
suppress : bool;
{ session }
let rec t = { session; events; voice_sessions }
and events = Session.events session |> Lwt_pipe.to_stream
and voice_sessions = SfMap.empty in
t
let disconnect t =
SfMap.to_seq t.voice_sessions
|> Seq.map (fun (_, { conn; _ }) -> Voice.disconnect conn)
|> Seq.to_list |> Lwt.join
>>= fun () ->
t.voice_sessions <- SfMap.empty;
Session.disconnect t.session
let user { session; _ } = Session.user session
let events { events; _ } = events |> Lwt_pipe.of_stream
let _fork_events t = Lwt_stream.clone t.events |> Lwt_pipe.of_stream
let leave_voice ~guild_id ({ session; voice_sessions; _ } as t) =
let open Lwt.Infix in
match SfMap.get guild_id voice_sessions with
| Some vs ->
Voice.disconnect vs.conn >>= fun () ->
t.voice_sessions <- SfMap.remove guild_id voice_sessions;
Session.send_voice_state_update session ~self_mute:true ~self_deaf:true
guild_id
| None -> Lwt.return_unit
let join_voice ~guild_id ~channel_id ({ session; _ } as t) =
let open Lwt.Syntax in
let user = Session.user session in
let join () =
let* () =
Session.send_voice_state_update session ~channel_id ~self_deaf:false
~self_mute:false guild_id
in
let is_own_vs
{ Events.VoiceState.guild_id = guild; channel_id = chan; user_id; _ } =
match (guild, chan) with
| Some g, Some c ->
Models.Snowflake.(guild_id = g && channel_id = c && user_id = user.id)
| _ -> false
in
let is_own_srv { Events.VoiceServerUpdate.guild_id = guild; _ } =
Models.Snowflake.(guild_id = guild)
in
let disconnect { session; _ } = Session.disconnect session
let wait_for_updates =
let rec f' ?st ?srv () =
let* evt = Lwt_pipe.read evs in
match ((evt : Events.t option), st, srv) with
| Some (VoiceStateUpdate st), _, None ->
L.debug (fun m -> m "got voice state");
f' ~st ?srv ()
| Some (VoiceServerUpdate srv), None, _ ->
L.debug (fun m -> m "got voice server");
f' ?st ~srv ()
| Some (VoiceStateUpdate st), _, Some srv
| Some (VoiceServerUpdate srv), Some st, _ ->
Lwt.return (st, srv)
| _ -> assert false
and evs =
_fork_events t
|> Lwt_pipe.Reader.filter ~f:(function
| Events.VoiceStateUpdate st -> is_own_vs st
| Events.VoiceServerUpdate srv -> is_own_srv srv
| _ -> false)
in
let p = f' () in
Lwt.on_termination p (fun () ->
L.info (fun m -> m "closing events fork");
Lwt_pipe.close_nonblock evs);
p
in
let open Lwt_result.Syntax in
let* st, srv =
Lwt.pick
[
Lwt_unix.sleep 5. |> Lwt.map (fun () -> `Timeout);
wait_for_updates |> Lwt.map (fun o -> `Ok o);
]
|> Lwt.map (function
| `Ok o -> Ok o
| `Timeout -> Error (`Discord "timed out waiting for update events"))
in
let cleanup _ =
L.warn (fun m -> m "cleanup");
match SfMap.get guild_id t.voice_sessions with
| Some { mixer; _ } ->
Mixer.destroy mixer;
t.voice_sessions <- SfMap.remove guild_id t.voice_sessions
| None -> ()
in
Voice.create ~on_destroy:cleanup ~server_id:guild_id ~user_id:user.id
~session_id:st.session_id ~token:srv.token srv.endpoint
in
let open Lwt_result.Syntax in
match SfMap.get guild_id t.voice_sessions with
| Some vs when Models.Snowflake.(vs.channel_id = channel_id) ->
L.info (fun m ->
m "there an active voice connection for channel '%Ld' already"
vs.channel_id);
Lwt_result.return vs
| Some _vs ->
L.info (fun m ->
m "already active voice session for guild %Ld, switching channel..."
guild_id);
let* conn = join () in
let+ mixer = Mixer.create conn |> Lwt_result.lift in
let vs = { conn; channel_id; mixer } in
t.voice_sessions <- SfMap.add guild_id vs t.voice_sessions;
vs
| None ->
let* conn = join () in
let+ mixer = Mixer.create conn |> Lwt_result.lift in
let vs = { conn; channel_id; mixer } in
t.voice_sessions <- SfMap.add guild_id vs t.voice_sessions;
vs
end
module GuildRequestMembers = struct
type t = {
guild_id : Models.Snowflake.t;
query : string option; [@yojson.option]
limit : int;
presences : bool option; [@yojson.option]
user_ids : Models.Snowflake.t list option; [@yojson.option]
nonce : string option; [@yojson.option]
}
[@@deriving yojson, show]
type q =
[ `All
| `User of Models.Snowflake.t
| `Users of Models.Snowflake.t list
| `Query of string
| `QueryLimit of string * int ]
let make ?presences ?nonce ~q guild_id =
let query, limit, user_ids =
match q with
| `All -> (Some "", 0, None)
| `User id -> (None, 0, Some [ id ])
| `Users users -> (None, 0, Some users)
| `QueryLimit (q, l) -> (Some q, l, None)
| `Query q -> (Some q, 0, None)
in
{ guild_id; query; limit; presences; user_ids; nonce }
let make_request_guild_members ?presences ?nonce ~q guild_id =
RequestGuildMembers (GuildRequestMembers.make ?presences ?nonce ~q guild_id)
type snowflake = Models.Snowflake.t
type bigstring = Bigstringaf.t
module Lwt_pipe = struct
include Lwt_pipe
(* TODO this hasn't actually been tested *)
let multicast ~n p =
assert (n > 1);
let main = create () in
let subs = Seq.(1 --^ n >|= (fun _ -> create ()) |> to_list) in
let running_pipes () = List.filter (fun p -> not @@ is_closed p) subs in
let rec fwd_rec () =
let open Lwt.Infix in
read p >>= function
| Some d ->
main :: running_pipes () |> Lwt_list.exists_p (fun p -> write p d)
>>= fun ok -> if ok then fwd_rec () else Lwt.return_unit
| None -> Lwt.return_unit
in
let fwd = fwd_rec () in
keep main fwd;
List.iter (fun p -> link_close p ~after:main) subs;
Lwt.on_termination fwd (fun () -> close_nonblock main);
(main, subs)
let fork p =
let p, sibs = multicast ~n:2 p in
(p, List.hd sibs)
end
open Globals
open Lwt.Infix
module L = (val Relog.logger ~namespace:__MODULE__ ())
type pcm_s16_frame =
(int, Bigarray.int16_signed_elt, Bigarray.c_layout) Bigarray.Array1.t
type pcm_f32_frame =
(float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array1.t
type silence_stream = bigstring Lwt_pipe.Reader.t
module Driver = struct
type t = {
mutable state : state;
mutable silence : silence_stream option;
mutable dead : bool;
}
and state = Idle | Playing of stream
and stream = { waker : waker; rx : bigstring Lwt_pipe.Reader.t }
and waker = unit Lwt.t * unit Lwt.u
let waker : unit -> waker = Lwt.task
let make_silence ?n () = Audio_stream.n_silence_pipe ?n ()
let create () =
{ state = Idle; silence = Some (make_silence ~n:20 ()); dead = false }
let now () = Mtime_clock.elapsed_ns ()
let destroy_active t =
match t.state with
| Playing s ->
Lwt_pipe.close_nonblock s.rx;
Lwt.cancel (fst s.waker);
t.state <- Idle
| Idle -> ()
let stop = destroy_active
let play ~s t =
match t.state with
| Playing _ ->
stop t;
t.silence <- Some (make_silence ());
t.state <- Playing s
| Idle -> t.state <- Playing s
let destroy t = if not t.dead then t.dead <- true
let run ~yield ~play ~stop t =
let rec exhaust ?(i = 0) p =
Lwt_pipe.read p >>= function
| Some frame ->
play frame >>= fun ok ->
if ok then exhaust ~i:(i + 1) p
else if i = 0 then failwith "need to send at least 1 frame"
else Lwt.return (`Yield i)
| None -> Lwt.return (`Closed i)
in
let framelen = float Rtp._FRAME_LEN /. 1e3 in
let schedule_next ?drift ?(frames = 1) () =
let timeout = float frames *. framelen in
let with_drift d =
let d = Lazy.force d in
let delta = Int64.(now () - d |> to_float) /. 1e9 in
timeout -. Float.min delta timeout
in
let timeout =
Option.map with_drift drift |> Option.get_or ~default:timeout
in
L.trace (fun m ->
m "sent %d frames, next tick in %f seconds" frames timeout);
Lwt_unix.sleep timeout >|= fun () -> `Tick
in
let rec yield_till tick =
let y = yield t >|= fun () -> if t.dead then `Dead else `Yield in
Lwt.choose [ tick; y ] >>= function
| `Dead ->
Lwt.cancel tick;
Lwt.return_unit
| `Yield -> yield_till tick
| `Tick ->
Lwt.cancel y;
Lwt.return_unit
in
let rec f' ?(drift = lazy (now ())) ?(i = 0) () =
match (t.silence, t.state) with
| _ when t.dead ->
destroy_active t;
Lwt.return_unit
| Some s, st -> (
exhaust s >>= function
| `Closed n ->
t.silence <- None;
(match st with Idle -> stop () | _ -> Lwt.return_unit)
>>= f' ~drift ~i:(i + n)
| `Yield n ->
let frames = i + n in
yield_till (schedule_next ~drift ~frames ()) >>= fun () -> f' ())
| None, Idle -> yield t >>= fun () -> f' ()
| None, Playing s -> (
exhaust s.rx >>= function
| `Closed n ->
t.silence <- Some (make_silence ());
t.state <- Idle;
Lwt.wakeup_later (snd s.waker) ();
f' ~drift ~i:(i + n) ()
| `Yield n ->
let frames = i + n in
yield_till (schedule_next ~drift ~frames ()) >>= fun () -> f' ())
in
f' ()
end
type t = { evloop_tx : evloop_msg Lwt_pipe.Writer.t }
and evloop_msg = Stop | Play of pcm_s16_frame Lwt_pipe.Reader.t * Driver.waker
let create_opus_encoder ?(frametype = `s16) () =
let open Opus in
let open Result.Infix in
let rec set_ctls ~l enc =
match l with
| ctl :: l -> Encoder.ctl enc ctl >>= fun () -> set_ctls ~l enc
| [] -> Ok enc
in
Encoder.create ~samplerate:Rtp._SAMPLE_RATE ~channels:`stereo
~application:Audio ()
>>= (fun enc ->
let shared =
CTL.
[
Set_signal `music;
Set_bitrate `max;
Set_complexity 10;
Set_packet_loss_perc 5;
Set_complexity 10;
Set_inband_FEC true;
Set_DTX false;
]
in
let ctls =
match frametype with
| `s16 -> CTL.(Set_LSB_depth 16) :: shared
| `f32 -> CTL.(Set_LSB_depth 24) :: shared
in
set_ctls ~l:ctls enc)
|> Result.map_err (fun e ->
`Msg (Printf.sprintf "opus error: %s" (Opus.Error.to_string e)))
let create ?(burst = 15) voice =
let ( let+ ) = Result.( let+ ) in
let chan = Lwt_pipe.create () in
let evloop_tx = Lwt_pipe.Writer.map ~f:(fun msg -> `Req msg) chan in
let+ encoder = create_opus_encoder () in
let encode =
let pkt_buf = Bigstringaf.create Rtp._VOICE_PACKET_MAX in
fun buf ->
match
Opus.Encoder.encode_blit encoder ~duration:Rtp._FRAME_LEN buf pkt_buf
with
| Ok `DTX ->
L.err (fun m -> m "DTX!!!");
None
| Ok (`Packet p) -> Some p
| Error e -> failwith ("opus error: " ^ Opus.Error.to_string e)
in
let driver = Driver.create () in
let yield driver =
Lwt.wrap_in_cancelable (Lwt_pipe.read chan)
>|= Option.get_or ~default:`Poison
>|= function
| `Req (Play (s, waker)) ->
let s = Lwt_pipe.Reader.filter_map ~f:encode s in
Driver.play driver ~s:{ waker; rx = s }
| `Req Stop -> Driver.stop driver
| `Poison -> Driver.destroy driver
in
let curr = ref 0 in
let play frame =
if !curr < burst then (
Voice.start_speaking voice >>= fun () ->
Voice.send_rtp voice frame >|= fun () ->
incr curr;
true)
else (
curr := 0;
Lwt.return false)
in
let stop () = Voice.stop_speaking voice in
let f = Driver.run ~yield ~play ~stop driver in
Lwt_pipe.keep chan f;
Lwt_pipe.link_close chan ~after:evloop_tx;
Lwt.on_termination f (fun () -> Lwt_pipe.close_nonblock chan);
{ evloop_tx }
let play ?k t stream =
let ((wp, _) as waker) = Driver.waker () in
let () = match k with Some f -> Lwt.on_success wp f | None -> () in
Lwt_pipe.write_exn t.evloop_tx (Play (stream, waker))
let destroy t = Lwt_pipe.close_nonblock t.evloop_tx
type t = string [@@deriving yojson]
type t = int64
let of_string = Int64.of_string
let to_string = Int64.to_string
let t_of_yojson : Yojson.Safe.t -> t = function
| `String s | `Intlit s -> of_string s
| _ -> assert false
let yojson_of_t t = `String (to_string t)
let discord_epoch = 1420070400000L
let timestamp t = CCInt64.((t lsr 22) + discord_epoch)
let worker_id t = CCInt64.((t land 0x3E0000L) lsr 17 |> to_int)
(* let t_of_yojson = function
| `String s | `Intlit s -> Int64.of_string s
| _ -> assert false *)
let increment t = CCInt64.(t land 0xFFFL |> to_int)
let pp fmt t =
Format.fprintf fmt
"@[(%Ld@[(ts=%Ld)@] @[(wid=%d)@] @[(pid=%d)@] @[(inc=%d)@])@]" t
(timestamp t) (worker_id t) (process_id t) (increment t)
let compare = Int64.compare
let ( = ) = Int64.equal
type t
type t = {
id : Snowflake.t;
username : string;
discriminator : string;
avatar : string option;
bot : bool option; [@yojson.option]
system : bool option; [@yojson.option]
mfa_enabled : bool option; [@yojson.option]
locale : string option; [@yojson.option]
verified : bool option; [@yojson.option]
email : string option option; [@yojson.option]
flags : int option; [@yojson.option]
premium_type : int option; [@yojson.option]
public_flags : int option; [@yojson.option]
}
[@@deriving yojson] [@@yojson.allow_extra_fields]
open Globals
let _SAMPLE_RATE = 48000
let _CHANNELS = 2
let _FRAME_LEN = 20
let _FRAME_SIZE = _SAMPLE_RATE / 1000 * _FRAME_LEN
(** Maximum packet size for a voice packet.
Set below Ethernet MTU to avoid fragmentation/rejection. *)
let _VOICE_PACKET_MAX = 1460
(* https://tools.ietf.org/html/rfc7587#section-4.2 *)
let ts_incr = Uint32.of_int @@ (48000 / 1000 * _FRAME_LEN)
module Sync = struct
type t = uint16 * uint32
let add_uint16_safe a b =
let open Uint16 in
if compare (max_int - b) a < 0 then a - (max_int - b) else a + b
let add_uint32_safe a b =
let open Uint32 in
if compare (max_int - b) a < 0 then a - (max_int - b) else a + b
let make () =
let seq = Random.(run (int Int.(2 ** 16))) |> Uint16.of_int in
let ts = Random.int64 Int64.(2L ** 32L) |> Uint32.of_int64 in
(seq, ts)
let seq = fst
let ts = snd
let tick (seq, ts) =
(add_uint16_safe seq Uint16.one, add_uint32_safe ts ts_incr)
end
type t = {
udp : Udp_connection.t;
mutable crypt : Udp_connection.crypt;
mutable sync : Sync.t;
}
let make ~udp ~crypt = { udp; crypt; sync = Sync.make () }
let ssrc { udp; _ } = udp.ssrc
let set_crypt t crypt = t.crypt <- crypt
let send_packet t bs =
let seq, ts = t.sync in
t.sync <- Sync.tick t.sync;
Udp_connection.send_voice_packet ~crypt:t.crypt ~seq ~ts ~audio:bs t.udp
let destroy t = Udp_connection.destroy t.udp
module Ws = struct
type t = t' ref
and t' = Open of Token_bucket.t * Ws_Conn.t | Closed
let create conn = ref (Open (Token_bucket.make ~capacity:2 1., conn))
let send t pl =
match !t with
| Open (tb, conn) ->
Lwt.(
Token_bucket.take tb >|= fun () ->
Ws_Conn.send conn pl;
Ok ())
| Closed -> Lwt.return (Error (`Msg "cannot send payload to closed ws"))
let send_exn t pl =
Lwt.(
send t pl >|= function
| Ok () -> ()
| Error e -> failwith (Error.to_string e))
let close ~code t =
match !t with
| Open (tb, conn) ->
t := Closed;
Token_bucket.cancel_waiting tb;
Ws_Conn.close ~code conn
| Closed -> ()
end
type info = { id : string; seq : int }
mutable state : state;
mutable ws : Ws_Conn.t;
mutable disconnect : unit -> unit;
ev_pipe : (Events.t, [ `r | `w ]) Lwt_pipe.t;
user : Models.User.t;
disconnect : unit -> unit Lwt.t;
ev_rx : Events.t Lwt_pipe.Reader.t;
pl_tx : Pl.send Lwt_pipe.Writer.t;
let session_logger : t -> (module Relog.Logger.S) =
fun t ->
Relog.clone
~fields:
F.
[
lazy_int "seq" (fun () ->
match t.state with
| Connected ({ seq; _ }, _)
| Greeting (Reconnection { seq; _ })
| Resuming ({ seq; _ }, _) ->
seq
| _ -> -1);
lazy_str "session_id" (fun () ->
match t.state with
| Connected ({ id; _ }, _)
| Greeting (Reconnection { id; _ })
| Resuming ({ id; _ }, _) ->
id
| _ -> "<not connected>");
lazy_bool "reconn" (fun () ->
match t.state with
| Resuming _ | Greeting (Reconnection _) -> true
| _ -> false);
]
(module L)
let state_reducer ~(session_logger : (module Relog.Logger.S)) ~forward_event
~send_payload ~on_ready ~token state pl =
let module L = (val session_logger) in
let do_handshake ~token ?reconn ws pl_rx =
let module L =
(val Relog.clone (module L) ~fields:F.[ bool "handshaking" true ])
in
let open Lwt_result.Syntax in
L.debug (fun m ->
m "sending heartbeat" ~fields:F.[ float "interval" interval ]);
Lwt.async (fun () -> Ws.send_exn ws Pl.heartbeat))
interval
in
let rec poll' st =
let* pl =
Lwt_pipe.read pl_rx >|= function
| Some (`Pl pl) -> Ok pl
| Some (`Closed code) -> Error (`Closed code)
| None -> assert false
in
match (st, pl) with
| Greet Fresh, Pl.Hello hb ->
let id = Pl.Identify.make token in
m "sending heartbeat" ~fields:F.[ float "hb_interval" interval ]);
send_payload Pl.heartbeat)
interval
m "got greeting, identifying (intents=%a)" Pl.Intents.pp id.intents);
let* () = Ws.send ws (Pl.Identify id) in
let hb_secs = Float.of_int hb /. 1_000. in
let hb = make_hb hb_secs in
poll' (Id hb)
|> Lwt_result.map_err (fun e ->
hb.cancel ();
e)
| Greet (Reconnection (info, ev_tx)), Hello hb ->
L.info (fun m ->
m "got greeting, resuming session '%s' with seq=%d" info.id info.seq);
let* () =
Ws.send ws (Pl.make_resume ~token ~session_id:info.id ~seq:info.seq)
in
let hb_secs = Float.of_int hb /. 1_000. in
let hb = make_hb hb_secs in
poll' (Resuming (info, ev_tx, hb))
|> Lwt_result.map_err (fun e ->
hb.cancel ();
e)
| (Greet _ as st), (Heartbeat | HeartbeatACK) ->
(* safe to ignore heartbeat related payloads during greeting
as we'll send an heartbeat as soon as we can *)
poll' st
| (Greet _ as st), _ ->
L.err (fun m ->
m
"!!!PROTOCOL VIOLATION!!! got something else other than Hello \
when greeting");
poll' st
| ((Id hb | Resuming (_, _, hb)) as st), Pl.Hello new_hb ->
L.info (fun m -> m "got new greeting, updating heartbeat");
let hb_secs = Float.of_int new_hb /. 1_000. in
hb.preempt ~interval:hb_secs ();
poll' st
| ((Id hb | Resuming (_, _, hb)) as st), Pl.Heartbeat ->
L.debug (fun m -> m "requested heartbeat, obliging...");
hb.preempt ();
poll' st
| ((Id hb | Resuming (_, _, hb)) as st), Pl.HeartbeatACK ->
L.debug (fun m -> m "got hearbeat ack");
hb.ack ();
poll' st
| Id hb, Dispatch (seq, Events.Ready info) ->
let id = info.session_id in
L.info (fun m ->
m "session is ready"
~fields:F.[ int "version" info.v; str "id" id; int "seq" seq ]);
Lwt_result.return (`Connected (info.user, { id; seq }, hb))
| Id _, InvalidSession _ ->
L.err (fun m -> m "session was invalidated while identifying");
Lwt_result.fail `Invalidated
| (Id _ as st), Dispatch _ ->
L.warn (fun m ->
m "ignoring non ready dispatch event during identification");
poll' st
| Resuming (info, _, hb), Dispatch (seq, Resumed) ->
L.info (fun m -> m "successfully resumed session '%s'" info.id);
Lwt_result.return (`Reconnected ({ info with seq }, hb))
| Resuming (info, ev_tx, hb), Dispatch (seq, ev) ->
L.debug (fun m ->
m "forwarding replayed event"
~fields:F.[ int "seq" seq; int "event_seq" seq ]);
let* () = Lwt_pipe.write_exn ev_tx ev |> Error.catch_lwt in
poll' (Resuming ({ info with seq }, ev_tx, hb))
| Resuming (_, _, hb), InvalidSession _ ->
let rand_wait =
let r = Random.(run (float_range 1. 5.)) in
(* only need precision up to ms *)
float (truncate (r *. 1e3)) /. 1e3
in
L.warn (fun m ->
m "couldn't resume session, waiting for %fs and identifying..."
rand_wait);
let id = Pl.Identify.make token in
L.info (fun m ->
m "got greeting, identifying (intents=%a)" Pl.Intents.pp id.intents);
let* () =
Lwt_unix.sleep rand_wait >>= fun () -> Ws.send ws (Pl.Identify id)
in
poll' (Id hb)
| _, Reconnect -> Lwt_result.fail `Retry
in
let c =
match reconn with
| Some (info, ev_tx) -> Reconnection (info, ev_tx)
| None -> Fresh
in
poll' (Greet c)
let create_conn uri =
let open Lwt_result.Syntax in
let+ conn = Ws_Conn.create ~zlib:false uri in
let p =
Lwt_pipe.of_stream (Ws_Conn.stream conn)
|> Lwt_pipe.Reader.map ~f:(function
| Ws_Conn.Payload pl -> `Pl pl
| Close code ->
L.warn (fun m ->
m "gateway ws session was closed: %a" Websocket.Close_code.pp
code);
`Closed code)
match (state, pl) with
| Greeting Fresh, Pl.Hello hb ->
let id = Pl.Identify.make token in
L.info (fun m ->
m "got greeting, identifying (intents=%a)" Pl.Intents.pp id.intents);
send_payload (Pl.Identify id);
let hb_secs = Float.of_int hb /. 1_000. in
let hb = make_hb hb_secs in
`Update (Identifying hb)
| Greeting (Reconnection ({ id; seq; _ } as info)), Hello hb ->
L.info (fun m ->
m "got greeting, resuming session '%s' with seq=%d" id seq);
send_payload (Pl.make_resume ~token ~session_id:id ~seq);
let hb_secs = Float.of_int hb /. 1_000. in
let hb = make_hb hb_secs in
`Update (Resuming (info, hb))
| Greeting _conn, InvalidSession _ ->
L.warn (fun m -> m "invalid session during initial greeting");
`Invalidated
| Greeting _, Heartbeat ->
L.warn (fun m -> m "got hearbeat request during greeting, ignoring...");
`NoUpdate
| Greeting _, HeartbeatACK ->
L.warn (fun m -> m "got hearbeat ack during handshake, ignoring...");
`NoUpdate
| Greeting Fresh, Reconnect ->
L.warn (fun m ->
m "got reconnection request during greeting, obliging...");
`Retry
| Greeting (Reconnection info), Reconnect ->
L.warn (fun m ->
m "got reconnection request during reconnection greeting, obliging...");
`RetryWith info
| Identifying hb, Dispatch (seq, Events.Ready info) ->
let s_id = info.session_id in
L.info (fun m ->
m "session is ready"
~fields:F.[ int "version" info.v; str "id" s_id; int "seq" seq ]);
on_ready ();
`Update (Connected ({ id = s_id; seq }, hb))
| (Identifying hb | Resuming (_, hb) | Connected (_, hb)), Hello new_hb ->
L.warn (fun m -> m "got new greeting, updating heartbeat_interval");
let hb_secs = Float.of_int new_hb /. 1_000. in
hb.preempt ~interval:hb_secs ();
`NoUpdate
| Identifying hb, InvalidSession _ ->
L.err (fun m -> m "session was invalidated while identifying");
hb.cancel ();
`Invalidated
| Identifying hb, Reconnect ->
L.warn (fun m -> m "got reconnection request while identifying");
hb.cancel ();
`Retry
| (Greeting _ | Identifying _), Dispatch _ ->
L.warn (fun m ->
m "received dispatch during initial handshake, ignoring...");
`NoUpdate
| (Identifying hb | Resuming (_, hb) | Connected (_, hb)), Heartbeat ->
L.info (fun m -> m "requested heartbeat, obliging...");
hb.preempt ();
`NoUpdate
| (Identifying hb | Resuming (_, hb) | Connected (_, hb)), HeartbeatACK ->
L.debug (fun m -> m "got hearbeat ack");
hb.ack ();
`NoUpdate
| Resuming (_, hb), InvalidSession _ ->
L.warn (fun m ->
m "couldn't resume session, waiting for %fs and identifying..." 3.4);
let id = Pl.Identify.make token in
L.info (fun m ->
m "got greeting, identifying (intents=%a)" Pl.Intents.pp id.intents);
Lwt.async (fun () ->
Lwt_unix.sleep 3.4
|> Lwt.map (fun () -> send_payload (Pl.Identify id)));
`Update (Identifying hb)
| Resuming (info, hb), Reconnect ->
hb.cancel ();
`RetryWith info
| Resuming (({ id; _ } as i), hb), Dispatch (e_seq, Resumed) ->
on_ready ();
L.info (fun m -> m "successfully resumed session '%s'" id);
`Update (Connected ({ i with seq = e_seq }, hb))
| Resuming (({ seq; _ } as i), hb), Dispatch (e_seq, e) ->
L.info (fun m ->
m "forwarding replayed event"
~fields:F.[ int "seq" seq; int "event_seq" e_seq ]);
forward_event e;
`Update (Connected ({ i with seq = e_seq }, hb))
| Connected (({ id; seq; _ } as info), hb), Reconnect ->
L.warn (fun m ->
m "got reconnection request" ~fields:F.[ str "id" id; int "seq" seq ]);
hb.cancel ();
`RetryWith info
| Connected (({ seq; id; _ } as info), hb), InvalidSession resume ->
L.warn (fun m ->
m "session invalidated" ~fields:F.[ bool "resumable" resume ]);
hb.cancel ();
if resume then (
L.info (fun m -> m "will try to resume session '%s' on seq=%d" id seq);
`RetryWith info)
else `Retry
| Connected (({ seq; _ } as i), hb), Dispatch (e_seq, e) ->
L.info (fun m ->
m "forwarding event"
~fields:F.[ int "seq" seq; int "event_seq" e_seq ]);
forward_event e;
`Update (Connected ({ i with seq = e_seq }, hb))
( Ws.create conn,
(p
: [ `Pl of Pl.recv | `Closed of Websocket.Close_code.t ] Lwt_pipe.Reader.t)
)
let rec manager ?t () =
let p_connected, u_connected = Lwt.wait () in
let p_closed, u_closed = Lwt.wait () in
let ws_conn_handler : Ws_Conn.handler =
fun ws ->
let disconnect () =
Lwt.wakeup_later u_closed `Disconnect;
Ws_Conn.close ~code:`Going_away ws
in
let t =
match t with
| Some t ->
t.ws <- ws;
t
| None ->
{
state = Greeting Fresh;
ws;
ev_pipe = Lwt_pipe.create ~max_size:10 ();
disconnect;
}
in
let module L = (val session_logger t) in
let forward_event ev =
Lwt.async (fun () ->
Lwt_pipe.write_exn t.ev_pipe ev
|> Lwt.map (fun () -> L.debug (fun m -> m "wrote to events pipe")))
in
let send_payload =
let bucket = Token_bucket.make ~capacity:1 2. in
fun pl ->
Lwt.async (fun () ->
Token_bucket.take bucket
|> Lwt.map (fun () -> Ws_Conn.send t.ws pl))
in
let on_ready () = Lwt.wakeup_later u_connected (Ok t) in
let invalidated = ref false in
let handle_payload =
let f' =
state_reducer
~session_logger:(module L)
~forward_event ~send_payload ~on_ready ~token
in
fun pl ->
match f' t.state pl with
| `NoUpdate -> ()
| `Update st -> t.state <- st
| `Retry ->
Ws_Conn.close ~code:`Normal_closure t.ws;
Lwt.wakeup_later u_closed (`Retry None)
| `RetryWith info ->
Ws_Conn.close ~code:`Abnormal_closure t.ws;
Lwt.wakeup_later u_closed (`Retry (Some info))
| `Invalidated -> invalidated := true
in
fun frame ->
match (frame, !invalidated) with
| Payload pl, false -> handle_payload pl
| Payload _, true -> ()
| Close code, _ ->
L.warn (fun m ->
m "session was closed with code %a" Websocket.Close_code.pp code);
let reason =
(* Make (or extend) type for Discord error codes *)
match code with
| `Other 4000 | `Other 4007 | `Other 4009 -> `Retry None
| `Other 4004 -> `Invalid "invalid token"
| _ -> `Invalid "unknown"
in
Lwt.wakeup_later u_closed reason
let ev_pipe = Lwt_pipe.create () in
let pl_pipe = Lwt_pipe.create () in
let read_exn p = Lwt_pipe.read p >|= Option.get_exn in
let dc = ref (fun () -> Lwt.return ()) in
let rec manage' ?session () =
let rec connect () =
let* ws, pipe = create_conn uri in
do_handshake ~token ?reconn:session ws pipe >>= function
| Ok res -> Lwt_result.return (ws, pipe, res)
| Error (`Closed _) ->
L.warn (fun m -> m "session closed during handshake");
Lwt_result.fail (`Discord "unrecoverable close code during handshake")
| Error `Invalidated ->
L.warn (fun m ->
m "session invalidated during handshake, invalid permissions?");
Lwt_result.fail (`Discord "unrecoverable close code during handshake")
| Error `Retry ->
L.warn (fun m -> m "retrying handshake");
connect ()
| Error #Error.t as e -> Lwt.return e
in
let* ws, pipe, res = connect () in
let bus =
Lwt_pipe.Reader.merge_all
[
pipe |> Lwt_pipe.Reader.map ~f:(fun pl -> `Ws pl);
pl_pipe |> Lwt_pipe.Reader.map ~f:(fun pl -> `Fwd pl);
]
in
let p_dc, u_dc = Lwt.wait () in
let p_dc'ed, u_dc'ed = Lwt.wait () in
(dc :=
fun () ->
if Lwt.is_sleeping p_dc then Lwt.wakeup_later u_dc `Dc;
p_dc'ed);
let info, hb =
match res with
| `Connected (user, info, hb) ->
if Lwt.is_sleeping p_init then
Lwt.wakeup_later u_init
(Ok
{
user;
disconnect = (fun () -> !dc ());
ev_rx = ev_pipe;
pl_tx = pl_pipe;
});
(ref info, hb)
| `Reconnected (info, hb) -> (ref info, hb)
let* () = Ws_Conn.create ~zlib ~handler:ws_conn_handler uri in
let* t = p_connected in
if Lwt.is_sleeping p_init then Lwt.wakeup_later u_init (Ok t);
let* reason = p_closed |> Lwt_result.ok in
match reason with
| `Retry None ->
t.state <- Greeting Fresh;
manager ~t ()
| `Retry (Some info) ->
t.state <- Greeting (Reconnection info);
manager ~t ()
| `Disconnect -> Lwt_result.return ()
| `Invalid msg -> Lwt_result.fail (`Discord msg)
let rec poll' () =
let open Lwt.Syntax in
let pl = read_exn bus in
let* res = Lwt.pick [ pl; p_dc ] in
match res with
| `Fwd pl -> Ws.send_exn ws pl >>= poll'
| `Ws (`Pl pl) -> handle_payload pl
| `Ws (`Closed code) ->
L.error (fun m ->
m "session closed with unrecoverable close code: %a"
Websocket.Close_code.pp code);
Lwt_result.fail
(`Discord
(Format.asprintf "unrecoverable close code: %a"
Websocket.Close_code.pp code))
| `Dc ->
Ws.close ~code:`Normal_closure ws;
Lwt_pipe.close_nonblock pipe;
Lwt_pipe.close_nonblock pl_pipe;
Lwt_pipe.close_nonblock bus;
Lwt.wakeup_later u_dc'ed ();
Lwt_result.return ()
and handle_payload = function
| Hello new_hb ->
L.warn (fun m -> m "got new greeting, updating heartbeat");
hb.preempt ~interval:(float new_hb /. 1e3) ();
poll' ()
| Heartbeat ->
L.debug (fun m -> m "requested hearbeat, obliging...");
hb.preempt ();
poll' ()
| HeartbeatACK ->
L.debug (fun m -> m "got heartbeat ack");
hb.ack ();
poll' ()
| InvalidSession resumable ->
L.warn (fun m -> m "session invalidated (resumable=%b)" resumable);
let session = if resumable then Some (!info, ev_pipe) else None in
hb.cancel ();
Lwt_pipe.close_nonblock bus;
(* TODO what to do in case of `false` again?? *)
manage' ?session ()
| Reconnect ->
L.warn (fun m -> m "got reconnection request, obliging...");
hb.cancel ();
Lwt_pipe.close_nonblock bus;
manage' ~session:(!info, ev_pipe) ()
| Dispatch (seq, Ready _) | Dispatch (seq, Resumed) ->
L.warn (fun m ->
m "ignoring handshake related payloads on established session");
info := { !info with seq };
poll' ()
| Dispatch (seq, ev) ->
info := { !info with seq };
Lwt_pipe.write ev_pipe ev >>= fun ok ->
if ok then poll' () else Lwt_result.return ()
in
poll' () >>= fun out ->
hb.cancel ();
Ws.close ~code:`Going_away ws;
Lwt_pipe.close_nonblock pipe;
Lwt_pipe.close_nonblock pl_pipe;
Lwt_pipe.close_nonblock bus;
Lwt_pipe.close ev_pipe >|= fun () -> out
let events { ev_pipe; _ } = ev_pipe
let user { user; _ } = user
let _send_exn { pl_tx; _ } pl = Lwt_pipe.write_exn pl_tx pl
let send_presence_update t ?since ~afk status =
_send_exn t (Pl.make_presence_update ?since ~afk status)
let send_voice_state_update t ?channel_id ?(self_mute = false)
?(self_deaf = false) guild_id =
_send_exn t
(Pl.make_voice_state_update ?channel_id ~self_mute ~self_deaf guild_id)
let send_guild_request_members t ?presences ?nonce ~q guild_id =
_send_exn t (Pl.make_request_guild_members ?presences ?nonce ~q guild_id)
let cancel_waiting t =
let rec f' () =
match CCDeque.take_front_opt t.waiters with
| Some (Waiter (_, _, p)) ->
Lwt.cancel p;
f' ()
| None -> ()
in
f' ()
open Globals
open Lwt.Infix
module L = (val Relog.logger ~namespace:__MODULE__ ())
module Packet = struct
module P = struct
open Angstrom
let is_num = function '0' .. '9' -> true | _ -> false
let is_null = function '\x00' -> true | _ -> false
module Ip = struct
let packet =
let* () =
BE.any_uint16 >>= function
| 2 -> return ()
| d -> fail (Printf.sprintf "expected response type (0x2), got %X" d)
in
let* len = BE.any_uint16 in
let* body_i = pos in
let* ssrc = BE.any_int32 >>| Int32.to_int in
let* addr_buf = take 64 in
let addr_p = take_while1 @@ Fun.(is_null %> not) in
let* addr =
match
Angstrom.parse_string ~consume:Angstrom.Consume.Prefix addr_p
addr_buf
with
| Ok a -> return a
| Error e -> fail e
in
let* port = BE.any_uint16 in
let+ () =
end_of_input
*> (pos >>= function
| n when n - body_i = len -> return ()
| n ->
fail
(Printf.sprintf
"expected body length of %d bytes, got %d bytes" len n))
in
(ssrc, addr, port)
end
end
module Ip = struct
let of_bigstring bs =
Angstrom.parse_bigstring ~consume:Angstrom.Consume.All P.Ip.packet bs
let write ~ssrc f =
Faraday.BE.write_uint16 f 0x1;
Faraday.BE.write_uint16 f 70;
Faraday.BE.write_uint32 f (Int32.of_int ssrc);
Faraday.write_bytes f (Bytes.create 66)
end
module Keep_alive = struct
let write ~ssrc f = Faraday.BE.write_uint32 f (Int32.of_int ssrc)
let interval = 5.
end
module RTP = struct
let header_len = 12
let write_header ~seq ~ts ~ssrc f =
let s = Faraday.pending_bytes f in
Faraday.write_uint8 f 0x80;
Faraday.write_uint8 f 0x78;
Faraday.BE.write_uint16 f Uint16.(to_int seq);
Faraday.BE.write_uint32 f Uint32.(to_int32 ts);
Faraday.BE.write_uint32 f Int32.(of_int ssrc);
assert (Faraday.pending_bytes f - s = header_len)
end
end
let ip_discovery ?(retries = 3) ?(timeout = 1.) ~ssrc sock =
let open Lwt.Syntax in
let buf = Bigstringaf.create 74 in
let timeout () =
Lwt_unix.sleep timeout |> Lwt.map (fun _ -> Error `Timeout)
in
let send_ip ~f ~ssrc sock =
Packet.Ip.write ~ssrc f;
let b = Faraday.serialize_to_string f |> Bytes.unsafe_of_string in
let len = Bytes.length b in
Lwt_unix.send sock b 0 len [] >|= fun n -> assert (n = len)
in
let recv_ip ~buf sock =
let open Lwt.Syntax in
let b = Bigstringaf.to_string buf |> Bytes.unsafe_of_string in
let* _ = Lwt_unix.read sock b 0 74 in
Bigstringaf.blit_from_bytes b ~src_off:0 buf ~dst_off:0 ~len:74;
let pkt = Packet.Ip.of_bigstring buf in
match pkt with Ok pkt -> Lwt.return pkt | Error msg -> failwith msg
in
let rec retry' n =
let f = Faraday.of_bigstring buf in
let* () = send_ip ~f ~ssrc sock in
Faraday.close f;
L.debug (fun m -> m "sent ip discovery request packet");
let* o = Lwt.pick [ timeout (); recv_ip ~buf sock |> Lwt_result.ok ] in
match o with
| Ok (_, ip, port) -> Lwt_result.return (ip, port)
| Error `Timeout when n > 0 ->
L.warn (fun m ->
m
"timed out (%dx) waiting for ip discovery response packet, \
retrying..."
(retries - n + 1));
retry' (n - 1)
| Error `Timeout ->
Lwt_result.fail "timed out waiting for ip discovery response"
in
retry' retries
type t = {
sock : Lwt_unix.file_descr;
local_addr : Unix.inet_addr * int;
discord_addr : Unix.inet_addr * int;
ssrc : int;
f : Faraday.t;
flush_packet : unit -> unit Lwt.t;
send_tx : [ `Flush | `Keep_alive ] Lwt_pipe.Writer.t;
}
type encryption_mode = Normal | Suffix | Lite of uint32 ref
let encryption_mode_of_string = function
| "xsalsa20_poly1305" -> Normal
| "xsalsa20_poly1305_suffix" -> Suffix
| "xsalsa20_poly1305_lite" ->
Lite (ref (Random.int64 Int64.(2L ** 32L) |> Uint32.of_int64))
| m -> raise @@ Invalid_argument ("unsupported encryption mode " ^ m)
type crypt = { mode : encryption_mode; secret : bytes }
let encrypt ~nonce ~secret data =
let nonce = Sodium.Secret_box.Bigbytes.to_nonce nonce in
let secret = Sodium.Secret_box.Bytes.to_key secret in
Sodium.Secret_box.Bigbytes.secret_box secret data nonce
let send_voice_packet ~crypt ~ts ~seq ~audio t =
let f = t.f in
Packet.RTP.write_header ~seq ~ts ~ssrc:t.ssrc f;
let encrypt nonce = encrypt audio ~nonce ~secret:crypt.secret in
let () =
match crypt.mode with
| Normal ->
let nonce = Faraday.create 24 in
Packet.RTP.write_header ~seq ~ts ~ssrc:t.ssrc nonce;
let padding =
String.make
(Sodium.Secret_box.nonce_size - Faraday.pending_bytes nonce)
'\x00'
in
Faraday.write_string nonce padding;
nonce |> Faraday.serialize_to_bigstring |> encrypt
|> Faraday.schedule_bigstring f
| Suffix ->
let nonce = Sodium.Secret_box.(random_nonce () |> Bigbytes.of_nonce) in
Faraday.schedule_bigstring f (encrypt nonce);
Faraday.schedule_bigstring f nonce
| Lite n ->
let nonce = Bigstringaf.create Sodium.Secret_box.nonce_size in
Bigstringaf.unsafe_set_int32_be nonce 0 (Uint32.to_int32 !n);
let _padding =
Seq.(
4 --^ Bigstringaf.length nonce
|> iter (fun i -> nonce.{i} <- '\x00'))
in
let next =
if Uint32.(compare !n max_int) = 0 then Uint32.zero
else Uint32.(!n + one)
in
n := next;
Faraday.schedule_bigstring f (encrypt nonce);
Faraday.schedule_bigstring f nonce
in
t.flush_packet ()
let create ~ssrc (ip, port) =
let open Lwt.Syntax in
let sock =
Lwt_unix.socket Unix.PF_INET Unix.SOCK_DGRAM
(Unix.getprotobyname "udp").Unix.p_proto
in
let* () = Lwt_unix.bind sock Unix.(ADDR_INET (inet_addr_any, 0)) in
let addr = Unix.inet_addr_of_string ip in
let* () = Lwt_unix.connect sock Unix.(ADDR_INET (addr, port)) in
let discord_addr = (addr, port) in
L.info (fun m ->
m "discovering external ip using discord's voice server: %s:%d" ip port);
let* ip_d, port_d =
ip_discovery ~ssrc sock
|> Lwt.map (function Ok d -> d | Error msg -> failwith msg)
in
L.info (fun m -> m "discovered ip and port: %s:%d" ip_d port_d);
let local_addr = Unix.(inet_addr_of_string ip_d, port_d) in
let f = Faraday.create (1024 * 4) in
let writev = Faraday_lwt_unix.writev_of_fd sock in
let send_tx = Lwt_pipe.create () in
let t =
{
f;
sock;
local_addr;
discord_addr;
ssrc;
flush_packet = (fun () -> Lwt_pipe.write send_tx `Flush >|= ignore);
send_tx;
}
in
let yield =
let keep_alive =
Lwt_stream.from (fun () ->
Lwt_unix.sleep Packet.Keep_alive.interval >|= fun () ->
Some `Keep_alive)
|> Lwt_pipe.of_stream
in
Lwt_pipe.connect ~ownership:`OutOwnsIn keep_alive send_tx;
fun f ->
Lwt_pipe.read send_tx >|= function
| Some `Keep_alive ->
L.debug (fun m ->
m "sending UDP keepalive packet"
~fields:
Relog.Field.
[
int "ssrc" ssrc;
float "interval" Packet.Keep_alive.interval;
]);
Packet.Keep_alive.write ~ssrc f
| Some `Flush -> ()
| None ->
L.debug (fun m -> m "closing udp socket");
Faraday.close f
in
let write_worker = Faraday_lwt_unix.serialize f ~yield ~writev in
let read_worker =
let open Lwt.Infix in
let b = Bytes.create (1024 * 4) in
let b_len = Bytes.length b in
let rec f () =
if Lwt_pipe.is_closed send_tx then Lwt.return_unit
else
let r = Lwt_unix.read sock b 0 b_len >|= fun n -> `read n in
let t = Lwt_unix.sleep (1. /. 5.) >|= fun () -> `timeout in
Lwt.pick [ r; t ] >>= function
| `read n ->
L.trace (fun m ->
m "got %d bytes from UDP (ssrc=%d) (rtcp? keepalive ack?)" n
ssrc);
f ()
| `timeout -> f ()
in
f ()
in
Lwt_pipe.keep send_tx write_worker;
Lwt_pipe.keep send_tx read_worker;
let+ () = Lwt_pipe.write_exn send_tx `Keep_alive in
t
let destroy { sock; send_tx; _ } =
match Lwt_unix.state sock with
| Lwt_unix.Opened ->
L.debug (fun m -> m "closing udp serializer");
Lwt_pipe.close_nonblock send_tx
| Closed | Aborted _ -> ()
let local_addr { local_addr; _ } = local_addr
let server_addr { discord_addr; _ } = discord_addr
open Globals
open Lwt.Infix
module L = (val Relog.logger ~namespace:__MODULE__ ())
module F = Relog.Field
module Ws_Conn = Websocket.Make (Voice_payload)
module Pl = Voice_payload
module Ws = struct
type t = t' ref
and t' = Open of Token_bucket.t * Ws_Conn.t | Closed
let create conn = ref (Open (Token_bucket.make ~capacity:2 1., conn))
let send t pl =
match !t with
| Open (tb, conn) ->
Lwt.(
Token_bucket.take tb >|= fun () ->
Ws_Conn.send conn pl;
Ok ())
| Closed -> Lwt.return (Error (`Msg "cannot send payload to closed ws"))
let send_exn t pl =
Lwt.(
send t pl >|= function
| Ok () -> ()
| Error e -> failwith (Error.to_string e))
let close ~code t =
match !t with
| Open (tb, conn) ->
t := Closed;
Token_bucket.cancel_waiting tb;
Ws_Conn.close ~code conn
| Closed -> ()
end
module Close_code = struct
type discord =
[ `Unknown_op
| `Invalid_payload
| `Not_authenticated
| `Authentication_failed
| `Already_authenticated
| `Invalid_session
| `Session_timeout
| `Server_not_found
| `Unknown_protocol
| `Disconnected
| `Voice_server_crashed
| `Unknown_encryption_mode ]
type t = [ Websocket.Close_code.standard | discord ]
let is_discord = function #discord -> true | _ -> false
let is_std = function #Websocket.Close_code.standard -> true | _ -> false
let to_int = function
| #Websocket.Close_code.standard as c -> Websocket.Close_code.to_int c
| `Unknown_op -> 4001
| `Invalid_payload -> 4002
| `Not_authenticated -> 4003
| `Authentication_failed -> 4004
| `Already_authenticated -> 4005
| `Invalid_session -> 4006
| `Session_timeout -> 4009
| `Server_not_found -> 4011
| `Unknown_protocol -> 4012
| `Disconnected -> 4014
| `Voice_server_crashed -> 4015
| `Unknown_encryption_mode -> 4016
let of_close_code_exn = function
| #Websocket.Close_code.standard as c -> c
| `Other 4001 -> `Unknown_op
| `Other 4002 -> `Invalid_payload
| `Other 4003 -> `Not_authenticated
| `Other 4004 -> `Authentication_failed
| `Other 4005 -> `Already_authenticated
| `Other 4006 -> `Invalid_session
| `Other 4009 -> `Session_timeout
| `Other 4011 -> `Server_not_found
| `Other 4012 -> `Unknown_protocol
| `Other 4014 -> `Disconnected
| `Other 4015 -> `Voice_server_crashed
| `Other 4016 -> `Unknown_encryption_mode
| `Other c -> failwith (Printf.sprintf "unknown voice close code: %d" c)
let pp =
let pp' fmt = function
| `Unknown_op -> Format.fprintf fmt "invalid opcode"
| `Invalid_payload ->
Format.fprintf fmt "invalid payload while identifying"
| `Not_authenticated -> Format.fprintf fmt "not authenticated"
| `Authentication_failed -> Format.fprintf fmt "authentication failed"
| `Already_authenticated -> Format.fprintf fmt "already authenticated"
| `Invalid_session -> Format.fprintf fmt "session is no longer valid"
| `Session_timeout -> Format.fprintf fmt "session timed out"
| `Server_not_found -> Format.fprintf fmt "voice server not found"
| `Unknown_protocol -> Format.fprintf fmt "unknown protocol"
| `Disconnected -> Format.fprintf fmt "disconnected"
| `Voice_server_crashed -> Format.fprintf fmt "voice server crashed"
| `Unknown_encryption_mode -> Format.fprintf fmt "unknown encryption mode"
in
fun fmt t ->
match t with
| #Websocket.Close_code.standard as c -> Websocket.Close_code.pp fmt c
| #discord as t -> Format.fprintf fmt "(%d %a)" (to_int t) pp' t
let is_recoverable = function
| `Unknown_op | `Invalid_payload | `Not_authenticated
| `Authentication_failed | `Already_authenticated | `Unknown_protocol
| `Disconnected | `Unknown_encryption_mode
| #Websocket.Close_code.standard ->
false
| _ -> true
end
type t = {
disconnect : unit -> unit Lwt.t;
ws_writer : Pl.send Lwt_pipe.Writer.t;
speak : bool Lwt_pipe.Writer.t;
rtp_writer : bigstring Lwt_pipe.Writer.t;
}
type hb = {
mutable interval : float;
mutable preempt : ?interval:float -> unit -> unit;
mutable ack : int -> unit;
mutable cancel : unit -> unit;
}
(* TODO Check if resuming also implies a fresh UDP handshake *)
type handshake_state =
| Greet of conn
| Id of hb
| Resuming of hb * session
| Establish_udp of hb * Udp_connection.t
and conn = Fresh | Reconnection of session
and session = { rtp : Rtp.t; mutable speaking : bool }
let make_heartbeat ?err fn interval =
let err =
Option.get_or
~default:(fun () -> failwith "no ACK of last heartbeat received")
err
in
let out =
{
interval;
preempt = (fun ?interval:_ -> ignore);
ack = ignore;
cancel = ignore;
}
in
let gen_nonce =
let st = Random.State.make_self_init () in
fun () -> Random.State.bits st
in
let rec loop () =
let open Lwt.Syntax in
let acked = ref false in
let nonce = gen_nonce () in
let () = fn nonce in
let p_preempt, u_preempt = Lwt.wait () in
let p_sleep = Lwt_unix.sleep out.interval |> Lwt.map (Fun.const `Sleep) in
out.ack <- (fun n -> if not !acked then acked := nonce = n);
out.cancel <-
(fun () ->
if Lwt.is_sleeping p_preempt then Lwt.wakeup_later u_preempt `Cancel);
out.preempt <-
(fun ?(interval = interval) () ->
if Lwt.is_sleeping p_preempt then
Lwt.wakeup_later u_preempt (`Preempt interval));
let* r = Lwt.pick [ p_sleep; p_preempt ] in
match (r, !acked) with
| `Sleep, true -> loop ()
| `Preempt interval, _ ->
out.interval <- interval;
loop ()
| `Sleep, false ->
err ();
Lwt.return ()
| `Cancel, _ -> Lwt.return ()
in
Lwt.async loop;
out
let secret_of_int_list l =
Seq.of_list l |> Seq.map Char.of_int_exn |> Bytes.of_seq
let with_ws_params ~version uri =
let uri = Uri.with_path uri "/" in
Uri.with_query uri [ ("v", [ Versions.Voice.to_string version ]) ]
let do_handshake ~server_id ~user_id ~session_id ~token ?session ws pl_pipe =
let open Lwt_result.Syntax in
let make_hb interval =
make_heartbeat
(fun nonce -> Lwt.async (fun () -> Ws.send_exn ws (Pl.heartbeat nonce)))
interval
in
let rec poll' st =
let* pl =
Lwt_pipe.read pl_pipe
|> Lwt.map (function
| Some (`Pl pl) -> Ok pl
| Some (`Closed code) -> Error (`Closed code)
| None -> assert false)
in
match (st, pl) with
| Greet Fresh, Pl.Hello hb ->
L.info (fun m -> m "got greeting, identifying");
let* () =
Ws.send ws (Pl.make_identify ~server_id ~user_id ~session_id ~token)
in
let hb_secs = Float.of_int hb /. 1e3 in
let hb = make_hb hb_secs in
poll' (Id hb)
| Greet (Reconnection session), Hello hb ->
L.info (fun m -> m "got greeting, resuming session '%s'" session_id);
let* () = Ws.send ws (Pl.make_resume ~server_id ~session_id ~token) in
let hb_secs = Float.of_int hb /. 1e3 in
let hb = make_hb hb_secs in
poll' (Resuming (hb, session))
| ( ((Id hb | Resuming (hb, _) | Establish_udp (hb, _)) as st),
Hello new_interval ) ->
let hb_secs = Float.of_int new_interval /. 1e3 in
L.warn (fun m -> m "got new greeting, updating heartbeat");
hb.preempt ~interval:hb_secs ();
poll' st
| ( ((Id hb | Resuming (hb, _) | Establish_udp (hb, _)) as st),
HeartbeatACK nonce ) ->
L.debug (fun m -> m "got hearbeat ack for nonce '%d'" nonce);
hb.ack nonce;
poll' st
| Resuming (hb, session), Resumed -> Lwt_result.return (hb, session)
| Id hb, Ready ({ ip; port; ssrc; _ } as info) ->
L.info (fun m ->
m
"voice ws session is ready, connecting to UDP voice server with:\n\
%a"
Pl.Ready.pp info);
let* udp = Udp_connection.create ~ssrc (ip, port) |> Error.catch_lwt in
let ip, port = Udp_connection.local_addr udp in
let address = Unix.string_of_inet_addr ip in
let* () =
Ws.send ws
(Pl.make_select_protocol ~address ~port ~mode:"xsalsa20_poly1305")
in
poll' (Establish_udp (hb, udp))
| Establish_udp (hb, udp), SessionDescription desc ->
L.info (fun m -> m "successfuly handshaked voice connection");
let secret = secret_of_int_list desc.secret_key in
let mode = Udp_connection.encryption_mode_of_string desc.mode in
let crypt = Udp_connection.{ secret; mode } in
Lwt_result.return (hb, { rtp = Rtp.make ~udp ~crypt; speaking = false })
| st, _pl ->
L.warn (fun m -> m "ignoring non-control payload during handshake");
poll' st
in
let c = match session with Some s -> Reconnection s | None -> Fresh in
poll' (Greet c)
let create_conn uri =
let open Lwt_result.Syntax in
let+ conn = Ws_Conn.create ~zlib:false uri in
let p =
Lwt_pipe.of_stream (Ws_Conn.stream conn)
|> Lwt_pipe.Reader.map ~f:(function
| Ws_Conn.Payload pl -> `Pl pl
| Close code ->
let code = Close_code.of_close_code_exn code in
L.warn (fun m ->
m "voice ws session was closed: %a" Close_code.pp code);
`Closed code)
in
( Ws.create conn,
(p : [ `Pl of Pl.recv | `Closed of Close_code.t ] Lwt_pipe.Reader.t) )
let create ?(on_destroy = fun _ -> ()) ?(version = Versions.Voice.V4) ~server_id
~user_id ~session_id ~token endpoint =
let open Lwt_result.Syntax in
let uri = Uri.of_string ("wss://" ^ endpoint) |> with_ws_params ~version in
let p_init, u_init = Lwt.wait () in
let ws_writer = Lwt_pipe.create () in
let rtp_writer = Lwt_pipe.create () in
let speak_pipe = Lwt_pipe.create () in
let read_exn p = Lwt_pipe.read p >|= Option.get_exn in
let dc = ref (fun () -> Lwt.return ()) in
let rec manage' ?session () =
let rec connect () =
let* ws, pipe = create_conn uri in
let res =
do_handshake ~server_id ~user_id ~session_id ~token ?session ws pipe
in
Lwt.bind res (function
| Ok (hb, session) -> Lwt_result.return (ws, pipe, hb, session)
| Error (`Closed code) when Close_code.is_recoverable code ->
L.warn (fun m ->
m "recoverable close code during handshake, retrying...");
connect ()
| Error (`Closed `Disconnected) ->
L.warn (fun m ->
m "disconnected during handshake, invalid permissions?");
Lwt.return
(Error (`Discord "voice session disconnected during handshake"))
| Error (`Closed _) ->
L.error (fun m -> m "unrecoverable close code during handshake");
assert false
| Error #Error.t as e -> Lwt.return e)
in
let* ws, pipe, hb, session = connect () in
let p_dc, u_dc = Lwt.wait () in
let p_dc'ed, u_dc'ed = Lwt.wait () in
(dc :=
fun () ->
Lwt.wakeup_later u_dc `Dc;
p_dc'ed);
if Lwt.is_sleeping p_init then
Lwt.wakeup_later u_init
(Ok
{
disconnect = (fun () -> !dc ());
ws_writer;
rtp_writer;
speak = speak_pipe;
});
let bus =
Lwt_pipe.Reader.merge_all
[
pipe |> Lwt_pipe.Reader.map ~f:(fun pl -> `Ws pl);
ws_writer |> Lwt_pipe.Reader.map ~f:(fun pl -> `Fwd pl);
speak_pipe |> Lwt_pipe.Reader.map ~f:(fun sp -> `Speak sp);
rtp_writer |> Lwt_pipe.Reader.map ~f:(fun pl -> `Fwd_rtp pl);
]
in
let rec poll' () =
let open Lwt.Syntax in
let pl = read_exn bus in
let* res = Lwt.pick [ pl; p_dc ] in
match res with
| `Fwd pl -> Ws.send_exn ws pl >>= poll'
| `Speak sp when Stdlib.(sp != session.speaking) ->
session.speaking <- sp;
Ws.send_exn ws
(Pl.make_speaking ~ssrc:(Rtp.ssrc session.rtp) ~delay:0
(if sp then 1 else 0))
>>= poll'
| `Speak _ -> poll' ()
| `Fwd_rtp audio -> Rtp.send_packet session.rtp audio >>= poll'
| `Ws (`Pl pl) -> handle_payload pl
| `Ws (`Closed code) when Close_code.is_recoverable code ->
L.warn (fun m ->
m "session closed with recoverable close code, retrying...");
session.speaking <- false;
hb.cancel ();
manage' ~session ()
| `Ws (`Closed code) ->
L.error (fun m ->
m "session closed with unrecoverable close code: %a" Close_code.pp
code);
Lwt.return
(Error (`Discord (Format.asprintf "%a" Close_code.pp code)))
| `Dc ->
Lwt_pipe.close_nonblock rtp_writer;
Rtp.destroy session.rtp;
Ws.close ~code:`Normal_closure ws;
Lwt_pipe.close_nonblock pipe;
Lwt_pipe.close_nonblock ws_writer;
Lwt_pipe.close_nonblock bus;
Lwt.wakeup_later u_dc'ed ();
Lwt.return (Ok ())
and handle_payload = function
| Hello new_hb ->
L.warn (fun m -> m "got new greeting, updating heartbeat");
hb.preempt ~interval:(Float.of_int new_hb /. 1e3) ();
poll' ()
| Ready info ->
L.error (fun m ->
m "got ready on established session, new voice server??@.%a"
Pl.Ready.pp info);
assert false
| SessionDescription desc ->
L.warn (fun m ->
m "got session description, updating...@.%a"
Pl.SessionDescription.pp desc);
let secret = secret_of_int_list desc.secret_key in
let mode = Udp_connection.encryption_mode_of_string desc.mode in
Rtp.set_crypt session.rtp Udp_connection.{ secret; mode };
poll' ()
| HeartbeatACK nonce ->
hb.ack nonce;
poll' ()
| Speaking _ | Resumed | ClientDisconnect ->
L.debug (fun m -> m "ignoring speaking/resumed/clientdisconnect");
poll' ()
in
poll' () >|= fun out ->
hb.cancel ();
Lwt_pipe.close_nonblock rtp_writer;
Rtp.destroy session.rtp;
Ws.close ~code:`Going_away ws;
Lwt_pipe.close_nonblock pipe;
Lwt_pipe.close_nonblock ws_writer;
Lwt_pipe.close_nonblock bus;
out
in
Lwt.async (fun () ->
manage' ()
|> Lwt.map (function
| Ok () -> ()
| Error e when Lwt.is_sleeping p_init ->
Lwt.wakeup_later u_init (Error e)
| Error e -> on_destroy e));
p_init
let _speak s { speak; _ } = Lwt_pipe.write_exn speak s
let start_speaking = _speak true
let stop_speaking = _speak false
let send_rtp { rtp_writer; _ } audio = Lwt_pipe.write_exn rtp_writer audio
let disconnect { disconnect; _ } = disconnect ()
module Hello = struct
let t_of_yojson json =
Yojson.Safe.Util.(
json |> member "heartbeat_interval" |> to_float |> Int.of_float)
end
module Identify = struct
type t = {
server_id : Models.Snowflake.t;
user_id : Models.Snowflake.t;
session_id : string;
token : string;
}
[@@deriving yojson, show] [@@yojson.allow_extra_fields]
let make ~server_id ~user_id ~session_id ~token =
{ server_id; user_id; session_id; token }
end
module Ready = struct
type t = { ssrc : int; ip : string; port : int; modes : string list }
[@@deriving yojson, show] [@@yojson.allow_extra_fields]
end
module SelectProtocol = struct
type t = { protocol : string; data : data }
and data = { address : string; port : int; mode : string }
[@@deriving yojson, show] [@@yojson.allow_extra_fields]
let make ~address ~port ~mode =
{ protocol = "udp"; data = { address; port; mode } }
end
module SessionDescription = struct
type t = { mode : string; secret_key : int list }
[@@deriving yojson, show] [@@yojson.allow_extra_fields]
end
module Resume = struct
type t = {
server_id : Models.Snowflake.t;
session_id : string;
token : string;
}
[@@deriving yojson, show] [@@yojson.allow_extra_fields]
let make ~server_id ~session_id ~token = { server_id; session_id; token }
end
module Speaking = struct
type t = {
speaking : int;
delay : int option; [@yojson.option]
ssrc : int option; [@yojson.option]
}
[@@deriving yojson, show] [@@yojson.allow_extra_fields]
let make ?delay ?ssrc speaking = { speaking; delay; ssrc }
end
| Identify : Dir.send t
| SelectProtocol : Dir.send t
| Ready : Dir.recv t
| Heartbeat : Dir.send t
| SessionDescription : Dir.recv t
| Speaking : _ Dir.bidi t
| HeartbeatACK : Dir.recv t
| Resume : Dir.send t
| Hello : Dir.recv t
| Identify : Identify.t -> Dir.send t
| SelectProtocol : SelectProtocol.t -> Dir.send t
| Ready : Ready.t -> Dir.recv t
| Heartbeat : int -> Dir.send t
| SessionDescription : SessionDescription.t -> Dir.recv t
| Speaking : Speaking.t -> _ Dir.bidi t
| HeartbeatACK : int -> Dir.recv t
| Resume : Resume.t -> Dir.send t
| Hello : int -> Dir.recv t
| Identify -> 0
| SelectProtocol -> 1
| Ready -> 2
| Heartbeat -> 3
| SessionDescription -> 4
| Speaking -> 5
| HeartbeatACK -> 6
| Resume -> 7
| Hello -> 8
| Identify _ -> 0
| SelectProtocol _ -> 1
| Ready _ -> 2
| Heartbeat _ -> 3
| SessionDescription _ -> 4
| Speaking _ -> 5
| HeartbeatACK _ -> 6
| Resume _ -> 7
| Hello _ -> 8
| 2, Some _d -> Ready
| 3, Some _d -> SessionDescription
| 5, Some _d -> Speaking
| 6, Some _d -> HeartbeatACK
| 8, Some _d -> Hello
| 9, Some _d -> Resumed
| 2, Some d -> Ready (Ready.t_of_yojson d)
| 4, Some d -> SessionDescription (SessionDescription.t_of_yojson d)
| 5, Some d -> Speaking (Speaking.t_of_yojson d)
| 6, Some d -> HeartbeatACK ([%of_yojson: int] d)
| 8, Some d -> Hello (Hello.t_of_yojson d)
| 9, _ -> Resumed
| Identify -> Raw.make ()
| SelectProtocol -> Raw.make ()
| Heartbeat -> Raw.make ()
| Speaking -> Raw.make ()
| Resume -> Raw.make ()
| Identify id -> Raw.make ~d:(Identify.yojson_of_t id) ()
| SelectProtocol sp -> Raw.make ~d:(SelectProtocol.yojson_of_t sp) ()
| Heartbeat nonce -> Raw.make ~d:(`Int nonce) ()
| Speaking d -> Raw.make ~d:(Speaking.yojson_of_t d) ()
| Resume d -> Raw.make ~d:(Resume.yojson_of_t d) ()
let heartbeat nonce = Heartbeat nonce
let make_identify ~server_id ~user_id ~session_id ~token =
Identify (Identify.make ~server_id ~user_id ~session_id ~token)
let make_select_protocol ~address ~port ~mode =
SelectProtocol (SelectProtocol.make ~address ~port ~mode)
let make_resume ~server_id ~session_id ~token =
Resume (Resume.make ~server_id ~session_id ~token)
let make_speaking ?ssrc ?delay s = Speaking (Speaking.make ?ssrc ?delay s)
let close ?code { close; _ } = close ?code ()
let send t (pl : send) =
L.debug (fun m ->
let pp = P.to_json pl |> Yojson.Safe.pretty_to_string in
m "sending payload:@.%s" pp);
let out = pl |> P.to_bytes in
let len = Bytes.length out in
let rec send' n =
match len - n with
| len when len > max_payload_len ->
Websocketaf.Wsd.send_bytes t.wsd ~kind:`Continuation out ~off:n
~len:max_payload_len;
send' (n + max_payload_len)
| len -> Websocketaf.Wsd.send_bytes t.wsd ~kind:`Text out ~off:n ~len
in
send' 0
let rec _connect :
enc:enc ->
zlib:bool ->
ssl:bool ->
string ->
int ->
string ->
handler:handler ->
(unit, [> `Msg of string ]) Lwt_result.t =
fun ~enc ~zlib ~ssl host port resource ~handler ->
let close ?code t = Websocketaf.Wsd.close ?code t.wsd
let rec _connect ~enc ~zlib ~ssl host port resource =
let send pl =
L.debug (fun m ->
let pp = P.to_json pl |> Yojson.Safe.pretty_to_string in
m "sending payload:@.%s" pp);
let out = pl |> P.to_bytes in
let len = Bytes.length out in
let rec send' n =
match len - n with
| len when len > max_payload_len ->
Websocketaf.Wsd.send_bytes wsd ~kind:`Text out ~off:n
~len:max_payload_len;
send' (n + max_payload_len)
| len -> Websocketaf.Wsd.send_bytes wsd ~kind:`Text out ~off:n ~len
let stream, push = Lwt_stream.create () in
Lwt.wakeup_later u (Ok { info = conn_info; wsd; stream });
let do_read ~on_done payload =
let buf = Faraday.create 1024 in
let on_eof () =
L.debug (fun m -> m "done reading!");
let out = Faraday.serialize_to_bigstring buf in
on_done out
let close_code =
Bigstringaf.get_int16_be bs off |> Close_code.of_int_exn
let on_done frame =
let close_code =
Bigstringaf.get_int16_be frame 0 |> Close_code.of_int_exn
in
L.warn (fun m ->
m "got close frame with code=%a" Close_code.pp close_code);
push (Some (Close close_code));
push None
let pl_json =
try
Bigstringaf.substring bs ~off ~len |> Yojson.Safe.from_string
with exn ->
L.err (fun m ->
m "invalid json payload"
~fields:F.[ str "exn" (Printexc.to_string exn) ]);
raise exn
in
L.debug (fun m ->
m "got websocket payload:@.%s"
(pl_json |> Yojson.Safe.pretty_to_string));
let () =
let on_done frame =
let pl_json =
try Bigstringaf.to_string frame |> Yojson.Safe.from_string
with exn ->
L.err (fun m ->
m "invalid json payload"
~fields:F.[ str "exn" (Printexc.to_string exn) ]);
raise exn
in
L.debug (fun m ->
m "got websocket payload:@.%s"
(pl_json |> Yojson.Safe.pretty_to_string));
Lwt.bind p (function
| Error (`Redir loc) ->
let host, port, ssl, resource = _uri_info (Uri.of_string loc) in
_connect ~enc ~zlib ~ssl host port resource ~handler
| Error (`Msg _) as err -> Lwt.return err
| Ok () -> Lwt.return (Ok ()))
p >>= function
| Error (`Redir loc) ->
let host, port, ssl, resource = _uri_info (Uri.of_string loc) in
_connect ~enc ~zlib ~ssl host port resource
| Error (`Msg _) as err -> Lwt.return err
| Ok t -> Lwt.return (Ok t)
"@opam/piaf":
"anmonteiro/piaf:piaf.opam#01601aeda4a415d335f61ac13fb738cdb7b834ea",
"@opam/websocketaf":
"link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf.opam",
"@opam/websocketaf-lwt":
"link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf-lwt.opam",
"@opam/websocketaf-lwt-unix":
"link:/Users/jcosta/Documents/Workspace/contrib/websocketaf/websocketaf-lwt-unix.opam",
"@opam/piaf": "anmonteiro/piaf:piaf.opam#01601aeda4a415d335f61ac13fb738cdb7b834ea",
"@opam/websocketaf": "quartz55/websocketaf:websocketaf.opam#d309d15",
"@opam/websocketaf-lwt": "quartz55/websocketaf:websocketaf-lwt.opam#d309d15",
"@opam/websocketaf-lwt-unix": "quartz55/websocketaf:websocketaf-lwt-unix.opam#d309d15",
"@opam/conf-libsodium": {
"source": "github:EduardoRFS/esy-libsodium:libsodium.opam#caeedd7",
"override": {
"dependencies": {
"esy-libsodium": "github:EduardoRFS/esy-libsodium#caeedd7"
}
}
},
"@opam/sodium": {
"source": "github:quartz55/ocaml-sodium:sodium.opam#6088c1c",
"override": {
"dependencies": {
"@opam/conf-libsodium": "*"
}
}
},
"@discopotty/opus": "link:./vendor/opus/package.json",
"@opam/conf-libopus": {
"source": "link:./vendor/esy-libopus/conf-libopus.opam",
"override": {
"dependencies": {
"esy-libopus": "./vendor/esy-libopus"
}
}
},
"esy-libopus": "./vendor/esy-libopus/package.json",
let setup_logging ?(level = Relog.Level.Debug) () =
let cli_fmter = Relog.Formatter.default ~color:true ~oneline:false () in
let cli_fmt = Format.formatter_of_out_channel stderr in
Relog.Sink.make (fun r ->
if Relog.(Level.compare (Record.level r) level) <= 0 then
cli_fmter cli_fmt r
else ())
|> Relog.Sink.set
opam-version: "2.0"
maintainer: "https://github.com/ocaml/opam-repository/issues"
homepage: "https://xiph.org/ogg/"
bug-reports: "https://github.com/ocaml/opam-repository/issues"
authors: "Xiph.Org Foundation"
license: "BSD"
build: ["pkg-config" "--exists" "ogg"]
depends: [
"conf-pkg-config" {build}
]
depexts: [
["libogg-dev"] {os-distribution = "alpine"}
["libogg"] {os-distribution = "arch"}
["libogg-dev"] {os-family = "debian"}
["libogg-devel"] {os-distribution = "centos"}
["libogg-devel"] {os-distribution = "fedora"}
["libogg-devel"] {os-family = "suse"}
["libogg"] {os-distribution = "nixos"}
["libogg"] {os-family = "bsd"}
["libogg"] {os = "macos" & os-distribution = "homebrew"}
]
synopsis: "Virtual package relying on libogg"
description:
"This package can only install if the ogg library is installed on the system."
flags: conf
{
"name": "esy-libogg",
"version": "1.3.1",
"description": "Mirror of libogg",
"license": "BSD",
"source": "https://downloads.xiph.org/releases/ogg/libogg-1.3.4.tar.gz#851cef020b346d44893e5d1c3dab83c675d479d9",
"override": {
"build": [
[
"./configure",
"--prefix=$cur__install",
"--disable-dependency-tracking"
],
[
"make",
"-j4"
]
],
"install": [
[
"make",
"install"
]
],
"buildsInSource": true,
"exportedEnv": {
"LD_LIBRARY_PATH": {
"val": "#{self.lib : $LD_LIBRARY_PATH}",
"scope": "global"
},
"OGG_LIB_PATH": {
"val": "#{self.lib}",
"scope": "global"
},
"OGG_INCLUDE_PATH": {
"val": "#{self.install / 'include'}",
"scope": "global"
},
"PKG_CONFIG_PATH": {
"val": "#{self.lib / 'pkgconfig' }:$PKG_CONFIG_PATH",
"scope": "global"
}
},
"dependencies": {
"@opam/conf-autoconf": "esy-packages/esy-autoconf:package.json#fb93edf",
"@opam/conf-pkg-config": "*"
}
}
}
opam-version: "2.0"
maintainer: "https://github.com/ocaml/opam-repository/issues"
homepage: "https://opus-codec.org/"
bug-reports: "https://github.com/ocaml/opam-repository/issues"
authors: "Xiph.Org Foundation"
license: "BSD"
build: ["pkg-config" "--exists" "opus"]
depends: [
"conf-pkg-config" {build}
]
depexts: [
["libopus-dev"] {os-distribution = "alpine"}
["libopus"] {os-distribution = "arch"}
["libopus-dev"] {os-family = "debian"}
["libopus-devel"] {os-distribution = "centos"}
["libopus-devel"] {os-distribution = "fedora"}
["libopus-devel"] {os-family = "suse"}
["libopus"] {os-distribution = "nixos"}
["libopus"] {os-family = "bsd"}
["libopus"] {os = "macos" & os-distribution = "homebrew"}
]
synopsis: "Virtual package relying on libopus"
description:
"This package can only install if the opus library is installed on the system."
flags: conf
{
"name": "esy-libopus",
"version": "1.3.1",
"description": "Mirror of libopus",
"license": "BSD",
"source": "https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#ed226536537861c9f0f1ef7ca79dffc225bc181b",
"override": {
"build": [
[
"./configure",
"--prefix=$cur__install"
],
[
"make",
"-j4"
]
],
"install": [
[
"make",
"install"
]
],
"buildsInSource": true,
"exportedEnv": {
"LD_LIBRARY_PATH": {
"val": "#{self.lib : $LD_LIBRARY_PATH}",
"scope": "global"
},
"OPUS_LIB_PATH": {
"val": "#{self.lib}",
"scope": "global"
},
"OPUS_INCLUDE_PATH": {
"val": "#{self.install / 'include'}",
"scope": "global"
},
"PKG_CONFIG_PATH": {
"val": "#{self.lib / 'pkgconfig' }:$PKG_CONFIG_PATH",
"scope": "global"
}
},
"dependencies": {
"@opam/conf-autoconf": "esy-packages/esy-autoconf:package.json#fb93edf",
"@opam/conf-pkg-config": "*"
}
}
}
(env
(dev
(flags
(:standard -warn-error -32))))
(lang dune 2.8)
(name opus)
# Set eol to LF so files aren't converted to CRLF-eol on Windows.
* text eol=lf linguist-generated
# Reset any possible .gitignore, we want all esy.lock to be un-ignored.
!*
{
"checksum": "b01887b77e04c37ac3b1e6a8b300ab10",
"root": "@discopotty/opus@link-dev:./package.json",
"node": {
"yarn-pkg-config@github:esy-ocaml/yarn-pkg-config#db3a0b63883606dd57c54a7158d560d6cba8cd79@d41d8cd9": {
"id":
"yarn-pkg-config@github:esy-ocaml/yarn-pkg-config#db3a0b63883606dd57c54a7158d560d6cba8cd79@d41d8cd9",
"name": "yarn-pkg-config",
"version":
"github:esy-ocaml/yarn-pkg-config#db3a0b63883606dd57c54a7158d560d6cba8cd79",
"source": {
"type": "install",
"source": [
"github:esy-ocaml/yarn-pkg-config#db3a0b63883606dd57c54a7158d560d6cba8cd79"
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"ocaml@4.11.2000@d41d8cd9": {
"id": "ocaml@4.11.2000@d41d8cd9",
"name": "ocaml",
"version": "4.11.2000",
"source": {
"type": "install",
"source": [
"archive:https://registry.npmjs.org/ocaml/-/ocaml-4.11.2000.tgz#sha1:ca152b7819a4dc9c00e2a9f788f8e62ddddef51d"
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"esy-m4@github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7@d41d8cd9": {
"id":
"esy-m4@github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7@d41d8cd9",
"name": "esy-m4",
"version":
"github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7",
"source": {
"type": "install",
"source": [
"github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7"
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"esy-libopus@archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b@a8705a59": {
"id":
"esy-libopus@archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b@a8705a59",
"name": "esy-libopus",
"version":
"archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b",
"source": {
"type": "install",
"source": [
"archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b"
]
},
"overrides": [ "../esy-libopus" ],
"dependencies": [
"@opam/conf-pkg-config@opam:1.3@93481236",
"@opam/conf-autoconf@github:esy-packages/esy-autoconf:package.json#fb93edf@d41d8cd9"
],
"devDependencies": []
},
"esy-libffi@github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c@d41d8cd9": {
"id":
"esy-libffi@github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c@d41d8cd9",
"name": "esy-libffi",
"version":
"github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c",
"source": {
"type": "install",
"source": [
"github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c"
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"esy-help2man@github:esy-packages/esy-help2man#c8e6931d1dcf58a81bd801145a777fd3b115c443@d41d8cd9": {
"id":
"esy-help2man@github:esy-packages/esy-help2man#c8e6931d1dcf58a81bd801145a777fd3b115c443@d41d8cd9",
"name": "esy-help2man",
"version":
"github:esy-packages/esy-help2man#c8e6931d1dcf58a81bd801145a777fd3b115c443",
"source": {
"type": "install",
"source": [
"github:esy-packages/esy-help2man#c8e6931d1dcf58a81bd801145a777fd3b115c443"
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"@opam/yojson@opam:1.7.0@7056d985": {
"id": "@opam/yojson@opam:1.7.0@7056d985",
"name": "@opam/yojson",
"version": "opam:1.7.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/b8/b89d39ca3f8c532abe5f547ad3b8f84d#md5:b89d39ca3f8c532abe5f547ad3b8f84d",
"archive:https://github.com/ocaml-community/yojson/releases/download/1.7.0/yojson-1.7.0.tbz#md5:b89d39ca3f8c532abe5f547ad3b8f84d"
],
"opam": {
"name": "yojson",
"version": "1.7.0",
"path": "esy.lock/opam/yojson.1.7.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/cppo@opam:1.6.7@c28ac3ae",
"@opam/biniou@opam:1.2.1@d7570399",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/biniou@opam:1.2.1@d7570399"
]
},
"@opam/uutf@opam:1.0.2@4440868f": {
"id": "@opam/uutf@opam:1.0.2@4440868f",
"name": "@opam/uutf",
"version": "opam:1.0.2",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/a7/a7c542405a39630c689a82bd7ef2292c#md5:a7c542405a39630c689a82bd7ef2292c",
"archive:http://erratique.ch/software/uutf/releases/uutf-1.0.2.tbz#md5:a7c542405a39630c689a82bd7ef2292c"
],
"opam": {
"name": "uutf",
"version": "1.0.2",
"path": "esy.lock/opam/uutf.1.0.2"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uchar@opam:0.0.2@c8218eea",
"@opam/topkg@opam:1.0.3@e4e10f1c",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@opam/cmdliner@opam:1.0.4@93208aac",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uchar@opam:0.0.2@c8218eea"
]
},
"@opam/uuseg@opam:13.0.0@f60712a7": {
"id": "@opam/uuseg@opam:13.0.0@f60712a7",
"name": "@opam/uuseg",
"version": "opam:13.0.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/a0/a07a97fff61da604614ea8da0547ef6a#md5:a07a97fff61da604614ea8da0547ef6a",
"archive:https://erratique.ch/software/uuseg/releases/uuseg-13.0.0.tbz#md5:a07a97fff61da604614ea8da0547ef6a"
],
"opam": {
"name": "uuseg",
"version": "13.0.0",
"path": "esy.lock/opam/uuseg.13.0.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uutf@opam:1.0.2@4440868f",
"@opam/uucp@opam:13.0.0@e9b515e0", "@opam/topkg@opam:1.0.3@e4e10f1c",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@opam/cmdliner@opam:1.0.4@93208aac",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uucp@opam:13.0.0@e9b515e0"
]
},
"@opam/uucp@opam:13.0.0@e9b515e0": {
"id": "@opam/uucp@opam:13.0.0@e9b515e0",
"name": "@opam/uucp",
"version": "opam:13.0.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/07/07e706249ddb2d02f0fa298804d3c739#md5:07e706249ddb2d02f0fa298804d3c739",
"archive:https://erratique.ch/software/uucp/releases/uucp-13.0.0.tbz#md5:07e706249ddb2d02f0fa298804d3c739"
],
"opam": {
"name": "uucp",
"version": "13.0.0",
"path": "esy.lock/opam/uucp.13.0.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uutf@opam:1.0.2@4440868f",
"@opam/topkg@opam:1.0.3@e4e10f1c",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@opam/cmdliner@opam:1.0.4@93208aac",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/uchar@opam:0.0.2@c8218eea": {
"id": "@opam/uchar@opam:0.0.2@c8218eea",
"name": "@opam/uchar",
"version": "opam:0.0.2",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/c9/c9ba2c738d264c420c642f7bb1cf4a36#md5:c9ba2c738d264c420c642f7bb1cf4a36",
"archive:https://github.com/ocaml/uchar/releases/download/v0.0.2/uchar-0.0.2.tbz#md5:c9ba2c738d264c420c642f7bb1cf4a36"
],
"opam": {
"name": "uchar",
"version": "0.0.2",
"path": "esy.lock/opam/uchar.0.0.2"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/tyxml@opam:4.4.0@1dca5713": {
"id": "@opam/tyxml@opam:4.4.0@1dca5713",
"name": "@opam/tyxml",
"version": "opam:4.4.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/51/516394dd4a5c31726997c51d66aa31cacb91e3c46d4e16c7699130e204042530#sha256:516394dd4a5c31726997c51d66aa31cacb91e3c46d4e16c7699130e204042530",
"archive:https://github.com/ocsigen/tyxml/releases/download/4.4.0/tyxml-4.4.0.tbz#sha256:516394dd4a5c31726997c51d66aa31cacb91e3c46d4e16c7699130e204042530"
],
"opam": {
"name": "tyxml",
"version": "4.4.0",
"path": "esy.lock/opam/tyxml.4.4.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uutf@opam:1.0.2@4440868f",
"@opam/seq@opam:base@d8d7de1d", "@opam/re@opam:1.9.0@d4d5e13d",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uutf@opam:1.0.2@4440868f",
"@opam/seq@opam:base@d8d7de1d", "@opam/re@opam:1.9.0@d4d5e13d",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/topkg@opam:1.0.3@e4e10f1c": {
"id": "@opam/topkg@opam:1.0.3@e4e10f1c",
"name": "@opam/topkg",
"version": "opam:1.0.3",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/e2/e285f7a296d77ee7d831ba9a6bfb396f#md5:e285f7a296d77ee7d831ba9a6bfb396f",
"archive:http://erratique.ch/software/topkg/releases/topkg-1.0.3.tbz#md5:e285f7a296d77ee7d831ba9a6bfb396f"
],
"opam": {
"name": "topkg",
"version": "1.0.3",
"path": "esy.lock/opam/topkg.1.0.3"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ocamlbuild@opam:0.14.0@6ac75d03"
]
},
"@opam/stdlib-shims@opam:0.3.0@0d088929": {
"id": "@opam/stdlib-shims@opam:0.3.0@0d088929",
"name": "@opam/stdlib-shims",
"version": "opam:0.3.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/ba/babf72d3917b86f707885f0c5528e36c63fccb698f4b46cf2bab5c7ccdd6d84a#sha256:babf72d3917b86f707885f0c5528e36c63fccb698f4b46cf2bab5c7ccdd6d84a",
"archive:https://github.com/ocaml/stdlib-shims/releases/download/0.3.0/stdlib-shims-0.3.0.tbz#sha256:babf72d3917b86f707885f0c5528e36c63fccb698f4b46cf2bab5c7ccdd6d84a"
],
"opam": {
"name": "stdlib-shims",
"version": "0.3.0",
"path": "esy.lock/opam/stdlib-shims.0.3.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/stdio@opam:v0.14.0@a624e254": {
"id": "@opam/stdio@opam:v0.14.0@a624e254",
"name": "@opam/stdio",
"version": "opam:v0.14.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/4c/4cbdf15f0be88c3258aaeff9e04e00e9#md5:4cbdf15f0be88c3258aaeff9e04e00e9",
"archive:https://ocaml.janestreet.com/ocaml-core/v0.14/files/stdio-v0.14.0.tar.gz#md5:4cbdf15f0be88c3258aaeff9e04e00e9"
],
"opam": {
"name": "stdio",
"version": "v0.14.0",
"path": "esy.lock/opam/stdio.v0.14.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@opam/base@opam:v0.14.1@d14008e2",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@opam/base@opam:v0.14.1@d14008e2"
]
},
"@opam/sexplib0@opam:v0.14.0@ddeb6438": {
"id": "@opam/sexplib0@opam:v0.14.0@ddeb6438",
"name": "@opam/sexplib0",
"version": "opam:v0.14.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/37/37aff0af8f8f6f759249475684aebdc4#md5:37aff0af8f8f6f759249475684aebdc4",
"archive:https://ocaml.janestreet.com/ocaml-core/v0.14/files/sexplib0-v0.14.0.tar.gz#md5:37aff0af8f8f6f759249475684aebdc4"
],
"opam": {
"name": "sexplib0",
"version": "v0.14.0",
"path": "esy.lock/opam/sexplib0.v0.14.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/seq@opam:base@d8d7de1d": {
"id": "@opam/seq@opam:base@d8d7de1d",
"name": "@opam/seq",
"version": "opam:base",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "seq",
"version": "base",
"path": "esy.lock/opam/seq.base"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/result@opam:1.5@6b753c82": {
"id": "@opam/result@opam:1.5@6b753c82",
"name": "@opam/result",
"version": "opam:1.5",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/1b/1b82dec78849680b49ae9a8a365b831b#md5:1b82dec78849680b49ae9a8a365b831b",
"archive:https://github.com/janestreet/result/releases/download/1.5/result-1.5.tbz#md5:1b82dec78849680b49ae9a8a365b831b"
],
"opam": {
"name": "result",
"version": "1.5",
"path": "esy.lock/opam/result.1.5"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/re@opam:1.9.0@d4d5e13d": {
"id": "@opam/re@opam:1.9.0@d4d5e13d",
"name": "@opam/re",
"version": "opam:1.9.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/bd/bddaed4f386a22cace7850c9c7dac296#md5:bddaed4f386a22cace7850c9c7dac296",
"archive:https://github.com/ocaml/ocaml-re/releases/download/1.9.0/re-1.9.0.tbz#md5:bddaed4f386a22cace7850c9c7dac296"
],
"opam": {
"name": "re",
"version": "1.9.0",
"path": "esy.lock/opam/re.1.9.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/ppxlib@opam:0.22.0@d2d2223a": {
"id": "@opam/ppxlib@opam:0.22.0@d2d2223a",
"name": "@opam/ppxlib",
"version": "opam:0.22.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/3e/3eeb91e03966662284a3222e612dee7f4fa2b7637c53d9572d2a74134bb96d7a#sha256:3eeb91e03966662284a3222e612dee7f4fa2b7637c53d9572d2a74134bb96d7a",
"archive:https://github.com/ocaml-ppx/ppxlib/releases/download/0.22.0/ppxlib-0.22.0.tbz#sha256:3eeb91e03966662284a3222e612dee7f4fa2b7637c53d9572d2a74134bb96d7a"
],
"opam": {
"name": "ppxlib",
"version": "0.22.0",
"path": "esy.lock/opam/ppxlib.0.22.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/sexplib0@opam:v0.14.0@ddeb6438",
"@opam/ppx_derivers@opam:1.2.1@ecf0aa45",
"@opam/ocaml-migrate-parsetree@opam:2.1.0@a3b6747d",
"@opam/ocaml-compiler-libs@opam:v0.12.3@f0f069bd",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/sexplib0@opam:v0.14.0@ddeb6438",
"@opam/ppx_derivers@opam:1.2.1@ecf0aa45",
"@opam/ocaml-migrate-parsetree@opam:2.1.0@a3b6747d",
"@opam/ocaml-compiler-libs@opam:v0.12.3@f0f069bd",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/ppx_yojson_conv_lib@opam:v0.14.0@116b53d6": {
"id": "@opam/ppx_yojson_conv_lib@opam:v0.14.0@116b53d6",
"name": "@opam/ppx_yojson_conv_lib",
"version": "opam:v0.14.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/e2/e23c5593a7211ad4fb09e26e9a74698a#md5:e23c5593a7211ad4fb09e26e9a74698a",
"archive:https://ocaml.janestreet.com/ocaml-core/v0.14/files/ppx_yojson_conv_lib-v0.14.0.tar.gz#md5:e23c5593a7211ad4fb09e26e9a74698a"
],
"opam": {
"name": "ppx_yojson_conv_lib",
"version": "v0.14.0",
"path": "esy.lock/opam/ppx_yojson_conv_lib.v0.14.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/ppx_derivers@opam:1.2.1@ecf0aa45": {
"id": "@opam/ppx_derivers@opam:1.2.1@ecf0aa45",
"name": "@opam/ppx_derivers",
"version": "opam:1.2.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/5d/5dc2bf130c1db3c731fe0fffc5648b41#md5:5dc2bf130c1db3c731fe0fffc5648b41",
"archive:https://github.com/ocaml-ppx/ppx_derivers/archive/1.2.1.tar.gz#md5:5dc2bf130c1db3c731fe0fffc5648b41"
],
"opam": {
"name": "ppx_derivers",
"version": "1.2.1",
"path": "esy.lock/opam/ppx_derivers.1.2.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/ppx_cstubs@opam:0.6.1.1@706c3a9f": {
"id": "@opam/ppx_cstubs@opam:0.6.1.1@706c3a9f",
"name": "@opam/ppx_cstubs",
"version": "opam:0.6.1.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/33/33e520e369da5630c697318f6f4ed26d#md5:33e520e369da5630c697318f6f4ed26d",
"archive:https://github.com/fdopen/ppx_cstubs/archive/0.6.1.1.tar.gz#md5:33e520e369da5630c697318f6f4ed26d"
],
"opam": {
"name": "ppx_cstubs",
"version": "0.6.1.1",
"path": "esy.lock/opam/ppx_cstubs.0.6.1.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/re@opam:1.9.0@d4d5e13d", "@opam/ppxlib@opam:0.22.0@d2d2223a",
"@opam/ocamlfind@opam:1.8.1@b7dc3072", "@opam/num@opam:1.4@a5195c8d",
"@opam/integers@opam:0.4.0@f7acfaeb",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/ctypes@opam:0.18.0@1be5c5e5",
"@opam/cppo@opam:1.6.7@c28ac3ae",
"@opam/containers@opam:3.2@c4e3f662",
"@opam/bigarray-compat@opam:1.0.0@3a87ad65",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/re@opam:1.9.0@d4d5e13d", "@opam/ppxlib@opam:0.22.0@d2d2223a",
"@opam/ocamlfind@opam:1.8.1@b7dc3072", "@opam/num@opam:1.4@a5195c8d",
"@opam/integers@opam:0.4.0@f7acfaeb",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/ctypes@opam:0.18.0@1be5c5e5",
"@opam/containers@opam:3.2@c4e3f662",
"@opam/bigarray-compat@opam:1.0.0@3a87ad65"
]
},
"@opam/odoc@opam:1.5.2@94f47c8b": {
"id": "@opam/odoc@opam:1.5.2@94f47c8b",
"name": "@opam/odoc",
"version": "opam:1.5.2",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/d2/d24463f2660bc28c72cda001478360158e953721c9e23fb361ec4783113c4871#sha256:d24463f2660bc28c72cda001478360158e953721c9e23fb361ec4783113c4871",
"archive:https://github.com/ocaml/odoc/releases/download/1.5.2/odoc-1.5.2.tbz#sha256:d24463f2660bc28c72cda001478360158e953721c9e23fb361ec4783113c4871"
],
"opam": {
"name": "odoc",
"version": "1.5.2",
"path": "esy.lock/opam/odoc.1.5.2"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/tyxml@opam:4.4.0@1dca5713",
"@opam/result@opam:1.5@6b753c82", "@opam/fpath@opam:0.7.3@674d8125",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/cppo@opam:1.6.7@c28ac3ae",
"@opam/cmdliner@opam:1.0.4@93208aac",
"@opam/astring@opam:0.8.5@1300cee8",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/tyxml@opam:4.4.0@1dca5713",
"@opam/result@opam:1.5@6b753c82", "@opam/fpath@opam:0.7.3@674d8125",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/cmdliner@opam:1.0.4@93208aac",
"@opam/astring@opam:0.8.5@1300cee8"
]
},
"@opam/ocamlformat@opam:0.17.0@643c4315": {
"id": "@opam/ocamlformat@opam:0.17.0@643c4315",
"name": "@opam/ocamlformat",
"version": "opam:0.17.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/68/68848b12e82dc1077a29f63d2777680e692b1a565276fcd00f06fb93cced3438#sha256:68848b12e82dc1077a29f63d2777680e692b1a565276fcd00f06fb93cced3438",
"archive:https://github.com/ocaml-ppx/ocamlformat/releases/download/0.17.0/ocamlformat-0.17.0.tbz#sha256:68848b12e82dc1077a29f63d2777680e692b1a565276fcd00f06fb93cced3438"
],
"opam": {
"name": "ocamlformat",
"version": "0.17.0",
"path": "esy.lock/opam/ocamlformat.0.17.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uutf@opam:1.0.2@4440868f",
"@opam/uuseg@opam:13.0.0@f60712a7",
"@opam/stdio@opam:v0.14.0@a624e254", "@opam/re@opam:1.9.0@d4d5e13d",
"@opam/ppxlib@opam:0.22.0@d2d2223a",
"@opam/odoc@opam:1.5.2@94f47c8b",
"@opam/ocaml-version@opam:3.1.0@a34970ed",
"@opam/ocaml-migrate-parsetree@opam:2.1.0@a3b6747d",
"@opam/menhirSdk@opam:20210310@5abaafca",
"@opam/menhirLib@opam:20210310@f9315713",
"@opam/menhir@opam:20210310@50de9216",
"@opam/fpath@opam:0.7.3@674d8125",
"@opam/fix@opam:20201120@5c318621",
"@opam/dune-build-info@opam:2.8.4@c3b98e33",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/cmdliner@opam:1.0.4@93208aac",
"@opam/base-unix@opam:base@87d0b2eb",
"@opam/base@opam:v0.14.1@d14008e2",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/uutf@opam:1.0.2@4440868f",
"@opam/uuseg@opam:13.0.0@f60712a7",
"@opam/stdio@opam:v0.14.0@a624e254", "@opam/re@opam:1.9.0@d4d5e13d",
"@opam/ppxlib@opam:0.22.0@d2d2223a",
"@opam/odoc@opam:1.5.2@94f47c8b",
"@opam/ocaml-version@opam:3.1.0@a34970ed",
"@opam/ocaml-migrate-parsetree@opam:2.1.0@a3b6747d",
"@opam/menhirSdk@opam:20210310@5abaafca",
"@opam/menhirLib@opam:20210310@f9315713",
"@opam/menhir@opam:20210310@50de9216",
"@opam/fpath@opam:0.7.3@674d8125",
"@opam/fix@opam:20201120@5c318621",
"@opam/dune-build-info@opam:2.8.4@c3b98e33",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/cmdliner@opam:1.0.4@93208aac",
"@opam/base-unix@opam:base@87d0b2eb",
"@opam/base@opam:v0.14.1@d14008e2"
]
},
"@opam/ocamlfind@opam:1.8.1@b7dc3072": {
"id": "@opam/ocamlfind@opam:1.8.1@b7dc3072",
"name": "@opam/ocamlfind",
"version": "opam:1.8.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/18/18ca650982c15536616dea0e422cbd8c#md5:18ca650982c15536616dea0e422cbd8c",
"archive:http://download2.camlcity.org/download/findlib-1.8.1.tar.gz#md5:18ca650982c15536616dea0e422cbd8c",
"archive:http://download.camlcity.org/download/findlib-1.8.1.tar.gz#md5:18ca650982c15536616dea0e422cbd8c"
],
"opam": {
"name": "ocamlfind",
"version": "1.8.1",
"path": "esy.lock/opam/ocamlfind.1.8.1"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__ocamlfind_opam__c__1.8.1_opam_override"
}
],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/conf-m4@opam:1@196bf219",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/ocamlbuild@opam:0.14.0@6ac75d03": {
"id": "@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"name": "@opam/ocamlbuild",
"version": "opam:0.14.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/87/87b29ce96958096c0a1a8eeafeb6268077b2d11e1bf2b3de0f5ebc9cf8d42e78#sha256:87b29ce96958096c0a1a8eeafeb6268077b2d11e1bf2b3de0f5ebc9cf8d42e78",
"archive:https://github.com/ocaml/ocamlbuild/archive/0.14.0.tar.gz#sha256:87b29ce96958096c0a1a8eeafeb6268077b2d11e1bf2b3de0f5ebc9cf8d42e78"
],
"opam": {
"name": "ocamlbuild",
"version": "0.14.0",
"path": "esy.lock/opam/ocamlbuild.0.14.0"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__ocamlbuild_opam__c__0.14.0_opam_override"
}
],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/ocaml-version@opam:3.1.0@a34970ed": {
"id": "@opam/ocaml-version@opam:3.1.0@a34970ed",
"name": "@opam/ocaml-version",
"version": "opam:3.1.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/ac/ac7ba16a09d8f72212742f3936980fbfaebb698c7bbf625182af7d6b2c3cde5f#sha256:ac7ba16a09d8f72212742f3936980fbfaebb698c7bbf625182af7d6b2c3cde5f",
"archive:https://github.com/ocurrent/ocaml-version/releases/download/v3.1.0/ocaml-version-v3.1.0.tbz#sha256:ac7ba16a09d8f72212742f3936980fbfaebb698c7bbf625182af7d6b2c3cde5f"
],
"opam": {
"name": "ocaml-version",
"version": "3.1.0",
"path": "esy.lock/opam/ocaml-version.3.1.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/ocaml-migrate-parsetree@opam:2.1.0@a3b6747d": {
"id": "@opam/ocaml-migrate-parsetree@opam:2.1.0@a3b6747d",
"name": "@opam/ocaml-migrate-parsetree",
"version": "opam:2.1.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/38/387b788ee4c0537f1fe02c25e05f0335af424828fc6fe940acc0db5948a5a71f#sha256:387b788ee4c0537f1fe02c25e05f0335af424828fc6fe940acc0db5948a5a71f",
"archive:https://github.com/ocaml-ppx/ocaml-migrate-parsetree/releases/download/v2.1.0/ocaml-migrate-parsetree-v2.1.0.tbz#sha256:387b788ee4c0537f1fe02c25e05f0335af424828fc6fe940acc0db5948a5a71f"
],
"opam": {
"name": "ocaml-migrate-parsetree",
"version": "2.1.0",
"path": "esy.lock/opam/ocaml-migrate-parsetree.2.1.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/ocaml-lsp-server@opam:1.4.1@cd85c376": {
"id": "@opam/ocaml-lsp-server@opam:1.4.1@cd85c376",
"name": "@opam/ocaml-lsp-server",
"version": "opam:1.4.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/ce/cee8371e7048e24c90e916c373ef6f3aba6f474d8a5fcf507ab6650fd8575eeb#sha256:cee8371e7048e24c90e916c373ef6f3aba6f474d8a5fcf507ab6650fd8575eeb",
"archive:https://github.com/ocaml/ocaml-lsp/releases/download/1.4.1/jsonrpc-1.4.1.tbz#sha256:cee8371e7048e24c90e916c373ef6f3aba6f474d8a5fcf507ab6650fd8575eeb"
],
"opam": {
"name": "ocaml-lsp-server",
"version": "1.4.1",
"path": "esy.lock/opam/ocaml-lsp-server.1.4.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/result@opam:1.5@6b753c82",
"@opam/ppx_yojson_conv_lib@opam:v0.14.0@116b53d6",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/dune-build-info@opam:2.8.4@c3b98e33",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/dot-merlin-reader@opam:4.1@120afa42",
"@opam/csexp@opam:1.4.0@bd1cb034", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/stdlib-shims@opam:0.3.0@0d088929",
"@opam/result@opam:1.5@6b753c82",
"@opam/ppx_yojson_conv_lib@opam:v0.14.0@116b53d6",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/dune-build-info@opam:2.8.4@c3b98e33",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/dot-merlin-reader@opam:4.1@120afa42",
"@opam/csexp@opam:1.4.0@bd1cb034"
]
},
"@opam/ocaml-compiler-libs@opam:v0.12.3@f0f069bd": {
"id": "@opam/ocaml-compiler-libs@opam:v0.12.3@f0f069bd",
"name": "@opam/ocaml-compiler-libs",
"version": "opam:v0.12.3",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/a8/a8403531439c14bbda2d504ef93610fd29a8e9520fc700f21889d893a513e3c9#sha256:a8403531439c14bbda2d504ef93610fd29a8e9520fc700f21889d893a513e3c9",
"archive:https://github.com/janestreet/ocaml-compiler-libs/releases/download/v0.12.3/ocaml-compiler-libs-v0.12.3.tbz#sha256:a8403531439c14bbda2d504ef93610fd29a8e9520fc700f21889d893a513e3c9"
],
"opam": {
"name": "ocaml-compiler-libs",
"version": "v0.12.3",
"path": "esy.lock/opam/ocaml-compiler-libs.v0.12.3"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/num@opam:1.4@a5195c8d": {
"id": "@opam/num@opam:1.4@a5195c8d",
"name": "@opam/num",
"version": "opam:1.4",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/cd/cda2b727e116a0b6a9c03902cc4b2415#md5:cda2b727e116a0b6a9c03902cc4b2415",
"archive:https://github.com/ocaml/num/archive/v1.4.tar.gz#md5:cda2b727e116a0b6a9c03902cc4b2415"
],
"opam": {
"name": "num",
"version": "1.4",
"path": "esy.lock/opam/num.1.4"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__num_opam__c__1.4_opam_override"
}
],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/merlin@opam:4.1-411@2ac33a62": {
"id": "@opam/merlin@opam:4.1-411@2ac33a62",
"name": "@opam/merlin",
"version": "opam:4.1-411",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/9e/9e2e6fc799c93ce1f2c7181645eafa37f64e43ace062b69218e1c29ac459937d#sha256:9e2e6fc799c93ce1f2c7181645eafa37f64e43ace062b69218e1c29ac459937d",
"archive:https://github.com/ocaml/merlin/releases/download/v4.1-411/merlin-v4.1-411.tbz#sha256:9e2e6fc799c93ce1f2c7181645eafa37f64e43ace062b69218e1c29ac459937d"
],
"opam": {
"name": "merlin",
"version": "4.1-411",
"path": "esy.lock/opam/merlin.4.1-411"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.4@ee414d6c",
"@opam/dot-merlin-reader@opam:4.1@120afa42",
"@opam/csexp@opam:1.4.0@bd1cb034", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/result@opam:1.5@6b753c82", "@opam/dune@opam:2.8.4@ee414d6c",
"@opam/dot-merlin-reader@opam:4.1@120afa42",
"@opam/csexp@opam:1.4.0@bd1cb034"
]
},
"@opam/menhirSdk@opam:20210310@5abaafca": {
"id": "@opam/menhirSdk@opam:20210310@5abaafca",
"name": "@opam/menhirSdk",
"version": "opam:20210310",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
],
"opam": {
"name": "menhirSdk",
"version": "20210310",
"path": "esy.lock/opam/menhirSdk.20210310"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/menhirLib@opam:20210310@f9315713": {
"id": "@opam/menhirLib@opam:20210310@f9315713",
"name": "@opam/menhirLib",
"version": "opam:20210310",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
],
"opam": {
"name": "menhirLib",
"version": "20210310",
"path": "esy.lock/opam/menhirLib.20210310"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/menhir@opam:20210310@50de9216": {
"id": "@opam/menhir@opam:20210310@50de9216",
"name": "@opam/menhir",
"version": "opam:20210310",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/1c/1cbc71c0bc1f3ddc3e71d5c1f919fd1a#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a",
"archive:https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz#md5:1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
],
"opam": {
"name": "menhir",
"version": "20210310",
"path": "esy.lock/opam/menhir.20210310"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/menhirSdk@opam:20210310@5abaafca",
"@opam/menhirLib@opam:20210310@f9315713",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/menhirSdk@opam:20210310@5abaafca",
"@opam/menhirLib@opam:20210310@f9315713",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/integers@opam:0.4.0@f7acfaeb": {
"id": "@opam/integers@opam:0.4.0@f7acfaeb",
"name": "@opam/integers",
"version": "opam:0.4.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/c1/c1492352e6525048790508c57aad93c3#md5:c1492352e6525048790508c57aad93c3",
"archive:https://github.com/ocamllabs/ocaml-integers/archive/0.4.0.tar.gz#md5:c1492352e6525048790508c57aad93c3"
],
"opam": {
"name": "integers",
"version": "0.4.0",
"path": "esy.lock/opam/integers.0.4.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/fpath@opam:0.7.3@674d8125": {
"id": "@opam/fpath@opam:0.7.3@674d8125",
"name": "@opam/fpath",
"version": "opam:0.7.3",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/07/0740b530e8fed5b0adc5eee8463cfc2f#md5:0740b530e8fed5b0adc5eee8463cfc2f",
"archive:https://erratique.ch/software/fpath/releases/fpath-0.7.3.tbz#md5:0740b530e8fed5b0adc5eee8463cfc2f"
],
"opam": {
"name": "fpath",
"version": "0.7.3",
"path": "esy.lock/opam/fpath.0.7.3"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/topkg@opam:1.0.3@e4e10f1c",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@opam/astring@opam:0.8.5@1300cee8",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/astring@opam:0.8.5@1300cee8"
]
},
"@opam/fix@opam:20201120@5c318621": {
"id": "@opam/fix@opam:20201120@5c318621",
"name": "@opam/fix",
"version": "opam:20201120",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/7e/7eb570b759635fe66f3556d2b1cc88e3#md5:7eb570b759635fe66f3556d2b1cc88e3",
"archive:https://gitlab.inria.fr/fpottier/fix/repository/20201120/archive.tar.gz#md5:7eb570b759635fe66f3556d2b1cc88e3"
],
"opam": {
"name": "fix",
"version": "20201120",
"path": "esy.lock/opam/fix.20201120"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/easy-format@opam:1.3.2@0484b3c4": {
"id": "@opam/easy-format@opam:1.3.2@0484b3c4",
"name": "@opam/easy-format",
"version": "opam:1.3.2",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/34/3440c2b882d537ae5e9011eb06abb53f5667e651ea4bb3b460ea8230fa8c1926#sha256:3440c2b882d537ae5e9011eb06abb53f5667e651ea4bb3b460ea8230fa8c1926",
"archive:https://github.com/mjambon/easy-format/releases/download/1.3.2/easy-format-1.3.2.tbz#sha256:3440c2b882d537ae5e9011eb06abb53f5667e651ea4bb3b460ea8230fa8c1926"
],
"opam": {
"name": "easy-format",
"version": "1.3.2",
"path": "esy.lock/opam/easy-format.1.3.2"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/dune-configurator@opam:2.8.4@5eab5258": {
"id": "@opam/dune-configurator@opam:2.8.4@5eab5258",
"name": "@opam/dune-configurator",
"version": "opam:2.8.4",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/4e/4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac",
"archive:https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
],
"opam": {
"name": "dune-configurator",
"version": "2.8.4",
"path": "esy.lock/opam/dune-configurator.2.8.4"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/csexp@opam:1.4.0@bd1cb034",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/csexp@opam:1.4.0@bd1cb034"
]
},
"@opam/dune-build-info@opam:2.8.4@c3b98e33": {
"id": "@opam/dune-build-info@opam:2.8.4@c3b98e33",
"name": "@opam/dune-build-info",
"version": "opam:2.8.4",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/4e/4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac",
"archive:https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
],
"opam": {
"name": "dune-build-info",
"version": "2.8.4",
"path": "esy.lock/opam/dune-build-info.2.8.4"
}
},
"overrides": [],
"dependencies": [
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "@opam/dune@opam:2.8.4@ee414d6c" ]
},
"@opam/dune@opam:2.8.4@ee414d6c": {
"id": "@opam/dune@opam:2.8.4@ee414d6c",
"name": "@opam/dune",
"version": "opam:2.8.4",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/4e/4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac",
"archive:https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz#sha256:4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
],
"opam": {
"name": "dune",
"version": "2.8.4",
"path": "esy.lock/opam/dune.2.8.4"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/base-unix@opam:base@87d0b2eb",
"@opam/base-threads@opam:base@36803084",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/base-unix@opam:base@87d0b2eb",
"@opam/base-threads@opam:base@36803084"
]
},
"@opam/dot-merlin-reader@opam:4.1@120afa42": {
"id": "@opam/dot-merlin-reader@opam:4.1@120afa42",
"name": "@opam/dot-merlin-reader",
"version": "opam:4.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/14/14a36d6fb8646a5df4530420a7861722f1a4ee04753717947305e3676031e7cd#sha256:14a36d6fb8646a5df4530420a7861722f1a4ee04753717947305e3676031e7cd",
"archive:https://github.com/ocaml/merlin/releases/download/v4.1/dot-merlin-reader-v4.1.tbz#sha256:14a36d6fb8646a5df4530420a7861722f1a4ee04753717947305e3676031e7cd"
],
"opam": {
"name": "dot-merlin-reader",
"version": "4.1",
"path": "esy.lock/opam/dot-merlin-reader.4.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/result@opam:1.5@6b753c82",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/csexp@opam:1.4.0@bd1cb034",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/yojson@opam:1.7.0@7056d985",
"@opam/result@opam:1.5@6b753c82",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/dune@opam:2.8.4@ee414d6c", "@opam/csexp@opam:1.4.0@bd1cb034"
]
},
"@opam/ctypes-foreign@opam:0.4.0@6d218780": {
"id": "@opam/ctypes-foreign@opam:0.4.0@6d218780",
"name": "@opam/ctypes-foreign",
"version": "opam:0.4.0",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "ctypes-foreign",
"version": "0.4.0",
"path": "esy.lock/opam/ctypes-foreign.0.4.0"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__ctypes_foreign_opam__c__0.4.0_opam_override"
}
],
"dependencies": [
"@opam/conf-libffi@opam:2.0.0@7c8981c5",
"@esy-ocaml/substs@0.0.1@d41d8cd9",
"@esy-ocaml/libffi@3.2.10@d41d8cd9"
],
"devDependencies": [ "@opam/conf-libffi@opam:2.0.0@7c8981c5" ]
},
"@opam/ctypes@opam:0.18.0@1be5c5e5": {
"id": "@opam/ctypes@opam:0.18.0@1be5c5e5",
"name": "@opam/ctypes",
"version": "opam:0.18.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/5d/5d9ef3790fda7cd97a8cec08be4b5b61#md5:5d9ef3790fda7cd97a8cec08be4b5b61",
"archive:https://github.com/ocamllabs/ocaml-ctypes/archive/0.18.0.tar.gz#md5:5d9ef3790fda7cd97a8cec08be4b5b61"
],
"opam": {
"name": "ctypes",
"version": "0.18.0",
"path": "esy.lock/opam/ctypes.0.18.0"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__ctypes_opam__c__0.18.0_opam_override"
}
],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/integers@opam:0.4.0@f7acfaeb",
"@opam/ctypes-foreign@opam:0.4.0@6d218780",
"@opam/bigarray-compat@opam:1.0.0@3a87ad65",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/integers@opam:0.4.0@f7acfaeb",
"@opam/bigarray-compat@opam:1.0.0@3a87ad65"
]
},
"@opam/csexp@opam:1.4.0@bd1cb034": {
"id": "@opam/csexp@opam:1.4.0@bd1cb034",
"name": "@opam/csexp",
"version": "opam:1.4.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/8e/8e3d6fca87f102a126dee8b72a2a0d146f10439c47218dfc149d51bf3edf364e#sha256:8e3d6fca87f102a126dee8b72a2a0d146f10439c47218dfc149d51bf3edf364e",
"archive:https://github.com/ocaml-dune/csexp/releases/download/1.4.0/csexp-1.4.0.tbz#sha256:8e3d6fca87f102a126dee8b72a2a0d146f10439c47218dfc149d51bf3edf364e"
],
"opam": {
"name": "csexp",
"version": "1.4.0",
"path": "esy.lock/opam/csexp.1.4.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/result@opam:1.5@6b753c82",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/cppo@opam:1.6.7@c28ac3ae": {
"id": "@opam/cppo@opam:1.6.7@c28ac3ae",
"name": "@opam/cppo",
"version": "opam:1.6.7",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/db/db553e3e6c206df09b1858c3aef5e21e56564d593642a3c78bcedb6af36f529d#sha256:db553e3e6c206df09b1858c3aef5e21e56564d593642a3c78bcedb6af36f529d",
"archive:https://github.com/ocaml-community/cppo/releases/download/v1.6.7/cppo-v1.6.7.tbz#sha256:db553e3e6c206df09b1858c3aef5e21e56564d593642a3c78bcedb6af36f529d"
],
"opam": {
"name": "cppo",
"version": "1.6.7",
"path": "esy.lock/opam/cppo.1.6.7"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@opam/base-unix@opam:base@87d0b2eb",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@opam/base-unix@opam:base@87d0b2eb"
]
},
"@opam/containers@opam:3.2@c4e3f662": {
"id": "@opam/containers@opam:3.2@c4e3f662",
"name": "@opam/containers",
"version": "opam:3.2",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/14/14787fb6878a94dd728a0ef7e368ab89#md5:14787fb6878a94dd728a0ef7e368ab89",
"archive:https://github.com/c-cube/ocaml-containers/archive/v3.2.tar.gz#md5:14787fb6878a94dd728a0ef7e368ab89"
],
"opam": {
"name": "containers",
"version": "3.2",
"path": "esy.lock/opam/containers.3.2"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/base-unix@opam:base@87d0b2eb",
"@opam/base-threads@opam:base@36803084",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/seq@opam:base@d8d7de1d",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/conf-pkg-config@opam:1.3@93481236": {
"id": "@opam/conf-pkg-config@opam:1.3@93481236",
"name": "@opam/conf-pkg-config",
"version": "opam:1.3",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "conf-pkg-config",
"version": "1.3",
"path": "esy.lock/opam/conf-pkg-config.1.3"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__conf_pkg_config_opam__c__1.3_opam_override"
}
],
"dependencies": [
"yarn-pkg-config@github:esy-ocaml/yarn-pkg-config#db3a0b63883606dd57c54a7158d560d6cba8cd79@d41d8cd9",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": []
},
"@opam/conf-m4@opam:1@196bf219": {
"id": "@opam/conf-m4@opam:1@196bf219",
"name": "@opam/conf-m4",
"version": "opam:1",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "conf-m4",
"version": "1",
"path": "esy.lock/opam/conf-m4.1"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__conf_m4_opam__c__1_opam_override"
}
],
"dependencies": [
"esy-m4@github:esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7@d41d8cd9",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": []
},
"@opam/conf-libopus@link:../esy-libopus/conf-libopus.opam": {
"id": "@opam/conf-libopus@link:../esy-libopus/conf-libopus.opam",
"name": "@opam/conf-libopus",
"version": "link:../esy-libopus/conf-libopus.opam",
"source": {
"type": "link",
"path": "../esy-libopus",
"manifest": "conf-libopus.opam"
},
"overrides": [
{ "dependencies": { "esy-libopus": "../esy-libopus" } }
],
"dependencies": [
"esy-libopus@archive:https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz#sha1:ed226536537861c9f0f1ef7ca79dffc225bc181b@a8705a59",
"@opam/conf-pkg-config@opam:1.3@93481236",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": []
},
"@opam/conf-libffi@opam:2.0.0@7c8981c5": {
"id": "@opam/conf-libffi@opam:2.0.0@7c8981c5",
"name": "@opam/conf-libffi",
"version": "opam:2.0.0",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "conf-libffi",
"version": "2.0.0",
"path": "esy.lock/opam/conf-libffi.2.0.0"
}
},
"overrides": [
{
"opamoverride":
"esy.lock/overrides/opam__s__conf_libffi_opam__c__2.0.0_opam_override"
}
],
"dependencies": [
"esy-libffi@github:esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c@d41d8cd9",
"@opam/conf-pkg-config@opam:1.3@93481236",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": []
},
"@opam/conf-autoconf@github:esy-packages/esy-autoconf:package.json#fb93edf@d41d8cd9": {
"id":
"@opam/conf-autoconf@github:esy-packages/esy-autoconf:package.json#fb93edf@d41d8cd9",
"name": "@opam/conf-autoconf",
"version": "github:esy-packages/esy-autoconf:package.json#fb93edf",
"source": {
"type": "install",
"source": [ "github:esy-packages/esy-autoconf:package.json#fb93edf" ]
},
"overrides": [],
"dependencies": [
"esy-help2man@github:esy-packages/esy-help2man#c8e6931d1dcf58a81bd801145a777fd3b115c443@d41d8cd9"
],
"devDependencies": []
},
"@opam/cmdliner@opam:1.0.4@93208aac": {
"id": "@opam/cmdliner@opam:1.0.4@93208aac",
"name": "@opam/cmdliner",
"version": "opam:1.0.4",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/fe/fe2213d0bc63b1e10a2d0aa66d2fc8d9#md5:fe2213d0bc63b1e10a2d0aa66d2fc8d9",
"archive:http://erratique.ch/software/cmdliner/releases/cmdliner-1.0.4.tbz#md5:fe2213d0bc63b1e10a2d0aa66d2fc8d9"
],
"opam": {
"name": "cmdliner",
"version": "1.0.4",
"path": "esy.lock/opam/cmdliner.1.0.4"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@opam/biniou@opam:1.2.1@d7570399": {
"id": "@opam/biniou@opam:1.2.1@d7570399",
"name": "@opam/biniou",
"version": "opam:1.2.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/sha256/35/35546c68b1929a8e6d27a3b39ecd17b38303a0d47e65eb9d1480c2061ea84335#sha256:35546c68b1929a8e6d27a3b39ecd17b38303a0d47e65eb9d1480c2061ea84335",
"archive:https://github.com/mjambon/biniou/releases/download/1.2.1/biniou-1.2.1.tbz#sha256:35546c68b1929a8e6d27a3b39ecd17b38303a0d47e65eb9d1480c2061ea84335"
],
"opam": {
"name": "biniou",
"version": "1.2.1",
"path": "esy.lock/opam/biniou.1.2.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/easy-format@opam:1.3.2@0484b3c4",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/bigarray-compat@opam:1.0.0@3a87ad65": {
"id": "@opam/bigarray-compat@opam:1.0.0@3a87ad65",
"name": "@opam/bigarray-compat",
"version": "opam:1.0.0",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/1c/1cc7c25382a8900bada34aadfd66632e#md5:1cc7c25382a8900bada34aadfd66632e",
"archive:https://github.com/mirage/bigarray-compat/archive/v1.0.0.tar.gz#md5:1cc7c25382a8900bada34aadfd66632e"
],
"opam": {
"name": "bigarray-compat",
"version": "1.0.0",
"path": "esy.lock/opam/bigarray-compat.1.0.0"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/base-unix@opam:base@87d0b2eb": {
"id": "@opam/base-unix@opam:base@87d0b2eb",
"name": "@opam/base-unix",
"version": "opam:base",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "base-unix",
"version": "base",
"path": "esy.lock/opam/base-unix.base"
}
},
"overrides": [],
"dependencies": [ "@esy-ocaml/substs@0.0.1@d41d8cd9" ],
"devDependencies": []
},
"@opam/base-threads@opam:base@36803084": {
"id": "@opam/base-threads@opam:base@36803084",
"name": "@opam/base-threads",
"version": "opam:base",
"source": {
"type": "install",
"source": [ "no-source:" ],
"opam": {
"name": "base-threads",
"version": "base",
"path": "esy.lock/opam/base-threads.base"
}
},
"overrides": [],
"dependencies": [ "@esy-ocaml/substs@0.0.1@d41d8cd9" ],
"devDependencies": []
},
"@opam/base@opam:v0.14.1@d14008e2": {
"id": "@opam/base@opam:v0.14.1@d14008e2",
"name": "@opam/base",
"version": "opam:v0.14.1",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/e4/e4419eae60f57e553b154856f0cacf42#md5:e4419eae60f57e553b154856f0cacf42",
"archive:https://github.com/janestreet/base/archive/v0.14.1.tar.gz#md5:e4419eae60f57e553b154856f0cacf42"
],
"opam": {
"name": "base",
"version": "v0.14.1",
"path": "esy.lock/opam/base.v0.14.1"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/sexplib0@opam:v0.14.0@ddeb6438",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c", "@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/sexplib0@opam:v0.14.0@ddeb6438",
"@opam/dune-configurator@opam:2.8.4@5eab5258",
"@opam/dune@opam:2.8.4@ee414d6c"
]
},
"@opam/astring@opam:0.8.5@1300cee8": {
"id": "@opam/astring@opam:0.8.5@1300cee8",
"name": "@opam/astring",
"version": "opam:0.8.5",
"source": {
"type": "install",
"source": [
"archive:https://opam.ocaml.org/cache/md5/e1/e148907c24157d1df43bec89b58b3ec8#md5:e148907c24157d1df43bec89b58b3ec8",
"archive:https://erratique.ch/software/astring/releases/astring-0.8.5.tbz#md5:e148907c24157d1df43bec89b58b3ec8"
],
"opam": {
"name": "astring",
"version": "0.8.5",
"path": "esy.lock/opam/astring.0.8.5"
}
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/topkg@opam:1.0.3@e4e10f1c",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/ocamlbuild@opam:0.14.0@6ac75d03",
"@esy-ocaml/substs@0.0.1@d41d8cd9"
],
"devDependencies": [ "ocaml@4.11.2000@d41d8cd9" ]
},
"@esy-ocaml/substs@0.0.1@d41d8cd9": {
"id": "@esy-ocaml/substs@0.0.1@d41d8cd9",
"name": "@esy-ocaml/substs",
"version": "0.0.1",
"source": {
"type": "install",
"source": [
"archive:https://registry.npmjs.org/@esy-ocaml/substs/-/substs-0.0.1.tgz#sha1:59ebdbbaedcda123fc7ed8fb2b302b7d819e9a46"
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"@esy-ocaml/libffi@3.2.10@d41d8cd9": {
"id": "@esy-ocaml/libffi@3.2.10@d41d8cd9",
"name": "@esy-ocaml/libffi",
"version": "3.2.10",
"source": {
"type": "install",
"source": [
"archive:https://registry.npmjs.org/@esy-ocaml/libffi/-/libffi-3.2.10.tgz#sha1:72697f135ee228b94294ec32f0d5b0fa313de403"
]
},
"overrides": [],
"dependencies": [],
"devDependencies": []
},
"@discopotty/opus@link-dev:./package.json": {
"id": "@discopotty/opus@link-dev:./package.json",
"name": "@discopotty/opus",
"version": "link-dev:./package.json",
"source": {
"type": "link-dev",
"path": ".",
"manifest": "package.json"
},
"overrides": [],
"dependencies": [
"ocaml@4.11.2000@d41d8cd9", "@opam/ppx_cstubs@opam:0.6.1.1@706c3a9f",
"@opam/ocamlfind@opam:1.8.1@b7dc3072",
"@opam/dune@opam:2.8.4@ee414d6c",
"@opam/ctypes-foreign@opam:0.4.0@6d218780",
"@opam/ctypes@opam:0.18.0@1be5c5e5",
"@opam/conf-libopus@link:../esy-libopus/conf-libopus.opam"
],
"devDependencies": [
"@opam/odoc@opam:1.5.2@94f47c8b",
"@opam/ocamlformat@opam:0.17.0@643c4315",
"@opam/ocaml-lsp-server@opam:1.4.1@cd85c376",
"@opam/merlin@opam:4.1-411@2ac33a62"
]
}
}
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: ["The astring programmers"]
homepage: "https://erratique.ch/software/astring"
doc: "https://erratique.ch/software/astring/doc"
dev-repo: "git+http://erratique.ch/repos/astring.git"
bug-reports: "https://github.com/dbuenzli/astring/issues"
tags: [ "string" "org:erratique" ]
license: "ISC"
depends: [
"ocaml" {>= "4.05.0"}
"ocamlfind" {build}
"ocamlbuild" {build}
"topkg" {build} ]
build: [[ "ocaml" "pkg/pkg.ml" "build" "--pinned" "%{pinned}%" ]]
synopsis: """Alternative String module for OCaml"""
description: """\
Astring exposes an alternative `String` module for OCaml. This module
tries to balance minimality and expressiveness for basic, index-free,
string processing and provides types and functions for substrings,
string sets and string maps.
Remaining compatible with the OCaml `String` module is a non-goal. The
`String` module exposed by Astring has exception safe functions,
removes deprecated and rarely used functions, alters some signatures
and names, adds a few missing functions and fully exploits OCaml's
newfound string immutability.
Astring depends only on the OCaml standard library. It is distributed
under the ISC license.
"""
url {
archive: "https://erratique.ch/software/astring/releases/astring-0.8.5.tbz"
checksum: "e148907c24157d1df43bec89b58b3ec8"
}
opam-version: "2.0"
maintainer: "https://github.com/ocaml/opam-repository/issues"
description: """
Threads library distributed with the OCaml compiler
"""
opam-version: "2.0"
maintainer: "https://github.com/ocaml/opam-repository/issues"
description: """
Unix library distributed with the OCaml compiler
"""
opam-version: "2.0"
maintainer: "opensource@janestreet.com"
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
homepage: "https://github.com/janestreet/base"
bug-reports: "https://github.com/janestreet/base/issues"
dev-repo: "git+https://github.com/janestreet/base.git"
doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/base/index.html"
license: "MIT"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.08.0"}
"sexplib0" {>= "v0.14" & < "v0.15"}
"dune" {>= "2.0.0"}
"dune-configurator"
]
synopsis: "Full standard library replacement for OCaml"
description: "
Full standard library replacement for OCaml
Base is a complete and portable alternative to the OCaml standard
library. It provides all standard functionalities one would expect
from a language standard library. It uses consistent conventions
across all of its module.
Base aims to be usable in any context. As a result system dependent
features such as I/O are not offered by Base. They are instead
provided by companion libraries such as stdio:
https://github.com/janestreet/stdio
"
url {
src: "https://github.com/janestreet/base/archive/v0.14.1.tar.gz"
checksum: "md5=e4419eae60f57e553b154856f0cacf42"
}
opam-version: "2.0"
synopsis: "Compatibility library to use Stdlib.Bigarray when possible"
maintainer: "Lucas Pluvinage <lucas.pluvinage@gmail.com>"
authors: "Lucas Pluvinage <lucas.pluvinage@gmail.com>"
license: "ISC"
homepage: "https://github.com/mirage/bigarray-compat"
bug-reports: "https://github.com/mirage/bigarray-compat/issues"
depends: [
"ocaml" {>= "4.02.3"}
"dune" {>= "1.0"}
]
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
]
dev-repo: "git+https://github.com/mirage/bigarray-compat.git"
url {
src: "https://github.com/mirage/bigarray-compat/archive/v1.0.0.tar.gz"
checksum: [
"md5=1cc7c25382a8900bada34aadfd66632e"
"sha512=c365fee15582aca35d7b05268cde29e54774ad7df7be56762b4aad78ca1409d4326ad3b34af0f1cc2c7b872837290a9cd9ff43b47987c03bba7bba32fe8a030f"
]
}
opam-version: "2.0"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
["dune" "build" "-p" name "@doc"] {with-doc}
]
maintainer: ["martin@mjambon.com"]
authors: ["Martin Jambon"]
bug-reports: "https://github.com/mjambon/biniou/issues"
homepage: "https://github.com/mjambon/biniou"
doc: "https://mjambon.github.io/biniou/"
license: "BSD-3-Clause"
dev-repo: "git+https://github.com/mjambon/biniou.git"
synopsis:
"Binary data format designed for speed, safety, ease of use and backward compatibility as protocols evolve"
description: """
Biniou (pronounced "be new") is a binary data format designed for speed, safety,
ease of use and backward compatibility as protocols evolve. Biniou is vastly
equivalent to JSON in terms of functionality but allows implementations several
times faster (4 times faster than yojson), with 25-35% space savings.
Biniou data can be decoded into human-readable form without knowledge of type
definitions except for field and variant names which are represented by 31-bit
hashes. A program named bdump is provided for routine visualization of biniou
data files.
The program atdgen is used to derive OCaml-Biniou serializers and deserializers
from type definitions.
Biniou format specification: mjambon.github.io/atdgen-doc/biniou-format.txt"""
depends: [
"easy-format"
"dune" {>= "1.10"}
"ocaml" {>= "4.02.3"}
]
url {
src:
"https://github.com/mjambon/biniou/releases/download/1.2.1/biniou-1.2.1.tbz"
checksum: [
"sha256=35546c68b1929a8e6d27a3b39ecd17b38303a0d47e65eb9d1480c2061ea84335"
"sha512=82670cc77bf3e869ee26e5fbe5a5affa45a22bc8b6c4bd7e85473912780e0111baca59b34a2c14feae3543ce6e239d7fddaeab24b686a65bfe642cdb91d27ebf"
]
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: ["Daniel Bünzli <daniel.buenzl i@erratique.ch>"]
homepage: "http://erratique.ch/software/cmdliner"
doc: "http://erratique.ch/software/cmdliner/doc/Cmdliner"
dev-repo: "git+http://erratique.ch/repos/cmdliner.git"
bug-reports: "https://github.com/dbuenzli/cmdliner/issues"
tags: [ "cli" "system" "declarative" "org:erratique" ]
license: "ISC"
depends:[ "ocaml" {>= "4.03.0"} ]
build: [[ make "all" "PREFIX=%{prefix}%" ]]
install:
[[make "install" "LIBDIR=%{_:lib}%" "DOCDIR=%{_:doc}%" ]
[make "install-doc" "LIBDIR=%{_:lib}%" "DOCDIR=%{_:doc}%" ]]
synopsis: """Declarative definition of command line interfaces for OCaml"""
description: """\
Cmdliner allows the declarative definition of command line interfaces
for OCaml.
It provides a simple and compositional mechanism to convert command
line arguments to OCaml values and pass them to your functions. The
module automatically handles syntax errors, help messages and UNIX man
page generation. It supports programs with single or multiple commands
and respects most of the [POSIX][1] and [GNU][2] conventions.
Cmdliner has no dependencies and is distributed under the ISC license.
[1]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html
[2]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
"""
url {
archive: "http://erratique.ch/software/cmdliner/releases/cmdliner-1.0.4.tbz"
checksum: "fe2213d0bc63b1e10a2d0aa66d2fc8d9"
}
opam-version: "2.0"
maintainer: "blue-prawn"
authors: ["Anthony Green"]
homepage: "http://sourceware.org/libffi/"
license: "MIT"
build: ["pkg-config" "libffi"]
depexts: [
["libffi"] {os = "macos" & os-distribution = "homebrew"}
["libffi"] {os = "macos" & os-distribution = "macports"}
["libffi-dev"] {os-distribution = "alpine"}
["libffi-dev"] {os-family = "debian"}
["libffi-devel"] {os-distribution = "centos"}
["libffi-devel"] {os-distribution = "fedora"}
["libffi-devel"] {os-distribution = "mageia"}
["libffi-devel"] {os-distribution = "ol"}
["libffi-devel"] {os-family = "suse"}
]
synopsis: "Virtual package relying on libffi system installation"
description: "This package can only install if libffi is installed on the system."
depends: ["conf-pkg-config" {build}]
bug-reports: "https://github.com/ocaml/opam-repository/issues"
flags: conf
opam-version: "2.0"
maintainer: "tim@gfxmonk.net"
homepage: "http://www.gnu.org/software/m4/m4.html"
bug-reports: "https://github.com/ocaml/opam-repository/issues"
authors: "GNU Project"
license: "GPL-3.0-only"
build: [["sh" "-exc" "echo | m4"]]
depexts: [
["m4"] {os-family = "debian"}
["m4"] {os-distribution = "fedora"}
["m4"] {os-distribution = "rhel"}
["m4"] {os-distribution = "centos"}
["m4"] {os-distribution = "alpine"}
["m4"] {os-distribution = "nixos"}
["m4"] {os-family = "suse"}
["m4"] {os-distribution = "ol"}
["m4"] {os-distribution = "arch"}
]
synopsis: "Virtual package relying on m4"
description:
"This package can only install if the m4 binary is installed on the system."
flags: conf
opam-version: "2.0"
maintainer: "unixjunkie@sdf.org"
authors: ["Francois Berenger"]
homepage: "http://www.freedesktop.org/wiki/Software/pkg-config/"
bug-reports: "https://github.com/ocaml/opam-repository/issues"
license: "GPL-1.0-or-later"
build: [
["pkg-config" "--help"]
]
install: [
["ln" "-s" "/usr/local/bin/pkgconf" "%{bin}%/pkg-config"] {os = "openbsd"}
]
remove: [
["rm" "-f" "%{bin}%/pkg-config"] {os = "openbsd"}
]
post-messages: [
"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"}
]
depexts: [
["pkg-config"] {os-family = "debian"}
["pkgconf"] {os-distribution = "arch"}
["pkgconfig"] {os-distribution = "fedora"}
["pkgconfig"] {os-distribution = "centos" & os-version <= "7"}
["pkgconfig"] {os-distribution = "mageia"}
["pkgconfig"] {os-distribution = "rhel" & os-version <= "7"}
["pkgconfig"] {os-distribution = "ol"}
["pkgconf"] {os-distribution = "alpine"}
["pkgconfig"] {os-distribution = "nixos"}
["devel/pkgconf"] {os = "openbsd"}
["pkg-config"] {os = "macos" & os-distribution = "homebrew"}
["pkgconfig"] {os = "macos" & os-distribution = "macports"}
["pkgconf"] {os = "freebsd"}
["pkgconf-pkg-config"] {os-distribution = "rhel" & os-version >= "8"}
["pkgconf-pkg-config"] {os-distribution = "centos" & os-version >= "8"}
["pkg-config"] {os-distribution = "cygwinports"}
]
synopsis: "Virtual package relying on pkg-config installation"
description: """
This package can only install if the pkg-config package is installed
on the system."""
flags: conf
opam-version: "2.0"
maintainer: "simon.cruanes.2007@m4x.org"
synopsis: "A modular, clean and powerful extension of the OCaml standard library"
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "build" "@doc" "-p" name ] {with-doc}
["dune" "runtest" "-p" name "-j" jobs] {with-test & ocaml:version < "4.11"}
]
depends: [
"ocaml" { >= "4.03.0" }
"dune" { >= "1.1" }
"dune-configurator"
"seq"
"qtest" { with-test }
"qcheck" { with-test }
"ounit" { with-test }
"iter" { with-test }
"gen" { with-test }
"uutf" { with-test }
"odoc" { with-doc }
]
depopts: [
"base-unix"
"base-threads"
]
tags: [ "stdlib" "containers" "iterators" "list" "heap" "queue" ]
homepage: "https://github.com/c-cube/ocaml-containers/"
doc: "https://c-cube.github.io/ocaml-containers"
dev-repo: "git+https://github.com/c-cube/ocaml-containers.git"
bug-reports: "https://github.com/c-cube/ocaml-containers/issues/"
authors: "Simon Cruanes"
url {
src: "https://github.com/c-cube/ocaml-containers/archive/v3.2.tar.gz"
checksum: [
"md5=14787fb6878a94dd728a0ef7e368ab89"
"sha512=9debbd79542fbe24e6b0ec5e0fb74077566663fa53b868aa381962653d65543a86606ed6703a75cf3e14962b66068747b237a88bb1eea15b6062665e294795ac"
]
}
opam-version: "2.0"
maintainer: "martin@mjambon.com"
authors: "Martin Jambon"
license: "BSD-3-Clause"
homepage: "https://github.com/ocaml-community/cppo"
doc: "https://ocaml-community.github.io/cppo/"
bug-reports: "https://github.com/ocaml-community/cppo/issues"
depends: [
"ocaml" {>= "4.02.3"}
"dune" {>= "1.0"}
"base-unix"
]
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
dev-repo: "git+https://github.com/ocaml-community/cppo.git"
synopsis: "Code preprocessor like cpp for OCaml"
description: """
Cppo is an equivalent of the C preprocessor for OCaml programs.
It allows the definition of simple macros and file inclusion.
Cppo is:
* more OCaml-friendly than cpp
* easy to learn without consulting a manual
* reasonably fast
* simple to install and to maintain
"""
x-commit-hash: "7d217864a5fdc4551699e248137a2f8b719d2078"
url {
src:
"https://github.com/ocaml-community/cppo/releases/download/v1.6.7/cppo-v1.6.7.tbz"
checksum: [
"sha256=db553e3e6c206df09b1858c3aef5e21e56564d593642a3c78bcedb6af36f529d"
"sha512=9722b50fd23aaccf86816313333a3bf8fc7c6b4ef06b153e5e1e1aaf14670cf51a4aac52fb1b4a0e5531699c4047a1eff6c24c969f7e5063e78096c2195b5819"
]
}
opam-version: "2.0"
synopsis: "Parsing and printing of S-expressions in Canonical form"
description: """
This library provides minimal support for Canonical S-expressions
[1]. Canonical S-expressions are a binary encoding of S-expressions
that is super simple and well suited for communication between
programs.
This library only provides a few helpers for simple applications. If
you need more advanced support, such as parsing from more fancy input
sources, you should consider copying the code of this library given
how simple parsing S-expressions in canonical form is.
To avoid a dependency on a particular S-expression library, the only
module of this library is parameterised by the type of S-expressions.
[1] https://en.wikipedia.org/wiki/Canonical_S-expressions
"""
maintainer: ["Jeremie Dimino <jeremie@dimino.org>"]
authors: [
"Quentin Hocquet <mefyl@gruntech.org>"
"Jane Street Group, LLC <opensource@janestreet.com>"
"Jeremie Dimino <jeremie@dimino.org>"
]
license: "MIT"
homepage: "https://github.com/ocaml-dune/csexp"
doc: "https://ocaml-dune.github.io/csexp/"
bug-reports: "https://github.com/ocaml-dune/csexp/issues"
depends: [
"dune" {>= "1.11"}
"ocaml" {>= "4.02.3"}
"result" {>= "1.5"}
]
dev-repo: "git+https://github.com/ocaml-dune/csexp.git"
build: [
["dune" "subst"] {pinned}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
# "@runtest" {with-test & ocaml:version >= "4.04"}
"@doc" {with-doc}
]
]
x-commit-hash: "0e1b2044c8d1ff187c27cec3e46d9cde14892650"
url {
src:
"https://github.com/ocaml-dune/csexp/releases/download/1.4.0/csexp-1.4.0.tbz"
checksum: [
"sha256=8e3d6fca87f102a126dee8b72a2a0d146f10439c47218dfc149d51bf3edf364e"
"sha512=604a5094fbbf61f497b342ad0aa8ec25275b2a904cd0c1823fc40daa54a15796b360374ff495c0d8ca3b4c1e6723b2ce37e030857fae131222606de818fb8129"
]
}
opam-version: "2.0"
maintainer: "yallop@gmail.com"
homepage: "https://github.com/ocamllabs/ocaml-ctypes"
dev-repo: "git+http://github.com/ocamllabs/ocaml-ctypes.git"
bug-reports: "http://github.com/ocamllabs/ocaml-ctypes/issues"
depends: [
"conf-libffi" {>= "2.0.0"}
]
tags: ["org:ocamllabs" "org:mirage"]
post-messages: [
"This package requires libffi on your system" {failure}
]
synopsis: "Virtual package for enabling the ctypes.foreign subpackage."
description: """
`ctypes-foreign` is just a virtual OPAM package that determines
whether the foreign subpackage should built as part of ctypes.
In order to actually get the ctypes package, you should also:
opam install ctypes ctypes-foreign
You can verify the existence of the ocamlfind subpackage by:
ocamlfind list | grep ctypes
Which should output something like:
ctypes (version: 0.4.1)
ctypes.foreign (version: 0.4.1)
ctypes.foreign.base (version: 0.4.1)
ctypes.foreign.threaded (version: 0.4.1)
ctypes.foreign.unthreaded (version: 0.4.1)
ctypes.stubs (version: 0.4.1)
ctypes.top (version: 0.4.1)"""
authors: "yallop@gmail.com"
opam-version: "2.0"
maintainer: "yallop@gmail.com"
homepage: "https://github.com/ocamllabs/ocaml-ctypes"
doc: "http://ocamllabs.github.io/ocaml-ctypes"
dev-repo: "git+http://github.com/ocamllabs/ocaml-ctypes.git"
bug-reports: "http://github.com/ocamllabs/ocaml-ctypes/issues"
license: "MIT"
build: [
[make "XEN=%{mirage-xen:enable}%" "libffi.config"]
{ctypes-foreign:installed}
["touch" "libffi.config"] {!ctypes-foreign:installed}
[make "XEN=%{mirage-xen:enable}%" "ctypes-base" "ctypes-stubs"]
[make "XEN=%{mirage-xen:enable}%" "ctypes-foreign"]
{ctypes-foreign:installed}
[make "test"] {with-test}
]
install: [
[make "install" "XEN=%{mirage-xen:enable}%"]
]
depends: [
"ocaml" {>= "4.02.3"}
"integers" { >= "0.3.0" }
"ocamlfind" {build}
"lwt" {with-test & >= "3.2.0"}
"ctypes-foreign" {with-test}
"ounit" {with-test}
"conf-ncurses" {with-test}
"bigarray-compat"
]
depopts: [
"ctypes-foreign"
"mirage-xen"
]
tags: ["org:ocamllabs" "org:mirage"]
synopsis: "Combinators for binding to C libraries without writing any C"
description: """
ctypes is a library for binding to C libraries using pure OCaml. The primary
aim is to make writing C extensions as straightforward as possible.
The core of ctypes is a set of combinators for describing the structure of C
types -- numeric types, arrays, pointers, structs, unions and functions. You
can use these combinators to describe the types of the functions that you want
to call, then bind directly to those functions -- all without writing or
generating any C!
To install the optional `ctypes.foreign` interface (which uses `libffi` to
provide dynamic access to foreign libraries), you will need to also install
the `ctypes-foreign` optional dependency:
opam install ctypes ctypes-foreign
This will make the `ctypes.foreign` ocamlfind subpackage available."""
authors: "yallop@gmail.com"
url {
src: "https://github.com/ocamllabs/ocaml-ctypes/archive/0.18.0.tar.gz"
checksum: "md5=5d9ef3790fda7cd97a8cec08be4b5b61"
}
conflicts: [
"mirage-xen" {>= "6.0.0"}
]
opam-version: "2.0"
maintainer: "defree@gmail.com"
authors: "The Merlin team"
synopsis: "Reads config files for merlin"
homepage: "https://github.com/ocaml/merlin"
bug-reports: "https://github.com/ocaml/merlin/issues"
dev-repo: "git+https://github.com/ocaml/merlin.git"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.06.1" }
"dune" {>= "2.7.0"}
"yojson" {>= "1.6.0"}
"ocamlfind" {>= "1.6.0"}
"csexp" {>= "1.2.3"}
"result" {>= "1.5"}
]
description:
"Helper process: reads .merlin files and gives the normalized content to merlin"
x-commit-hash: "ab02f60994c81166820791b5f465f467d752b8dc"
url {
src:
"https://github.com/ocaml/merlin/releases/download/v4.1/dot-merlin-reader-v4.1.tbz"
checksum: [
"sha256=14a36d6fb8646a5df4530420a7861722f1a4ee04753717947305e3676031e7cd"
"sha512=65fd4ab08904c05651a7ef8971802ffaa428daa920765dbcf162e3c56e8047e4c9e4356daa45efccce7c73a586635c8f6cf8118fd3059789de9aff68579bd436"
]
}
opam-version: "2.0"
synopsis: "Embed build informations inside executable"
description: """
The build-info library allows to access information about how the
executable was built, such as the version of the project at which it
was built or the list of statically linked libraries with their
versions. It supports reporting the version from the version control
system during development to get an precise reference of when the
executable was built.
"""
maintainer: ["Jane Street Group, LLC <opensource@janestreet.com>"]
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
license: "MIT"
homepage: "https://github.com/ocaml/dune"
doc: "https://dune.readthedocs.io/"
bug-reports: "https://github.com/ocaml/dune/issues"
depends: [
"dune" {>= "2.8"}
"odoc" {with-doc}
]
dev-repo: "git+https://github.com/ocaml/dune.git"
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@doc" {with-doc}
]
]
x-commit-hash: "b6a3f66fb15378fc7170e94778f4d2c0b142ad92"
url {
src: "https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz"
checksum: [
"sha256=4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"sha512=efc1834c4add40138a101734665a1f462c19fe76d1cbb457b1fc20f95991118a50b24d485fb98d39046e41bec03885a8dc071bf8add51083ac9780bff9f6668a"
]
}
opam-version: "2.0"
synopsis: "Helper library for gathering system configuration"
description: """
dune-configurator is a small library that helps writing OCaml scripts that
test features available on the system, in order to generate config.h
files for instance.
Among other things, dune-configurator allows one to:
- test if a C program compiles
- query pkg-config
- import #define from OCaml header files
- generate config.h file
"""
maintainer: ["Jane Street Group, LLC <opensource@janestreet.com>"]
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
license: "MIT"
homepage: "https://github.com/ocaml/dune"
doc: "https://dune.readthedocs.io/"
bug-reports: "https://github.com/ocaml/dune/issues"
depends: [
"dune" {>= "2.8"}
"ocaml" {>= "4.03.0"}
"result"
"csexp" {>= "1.3.0"}
"odoc" {with-doc}
]
dev-repo: "git+https://github.com/ocaml/dune.git"
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@doc" {with-doc}
]
]
x-commit-hash: "b6a3f66fb15378fc7170e94778f4d2c0b142ad92"
url {
src: "https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz"
checksum: [
"sha256=4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"sha512=efc1834c4add40138a101734665a1f462c19fe76d1cbb457b1fc20f95991118a50b24d485fb98d39046e41bec03885a8dc071bf8add51083ac9780bff9f6668a"
]
}
opam-version: "2.0"
synopsis: "Fast, portable, and opinionated build system"
description: """
dune is a build system that was designed to simplify the release of
Jane Street packages. It reads metadata from "dune" files following a
very simple s-expression syntax.
dune is fast, has very low-overhead, and supports parallel builds on
all platforms. It has no system dependencies; all you need to build
dune or packages using dune is OCaml. You don't need make or bash
as long as the packages themselves don't use bash explicitly.
dune supports multi-package development by simply dropping multiple
repositories into the same directory.
It also supports multi-context builds, such as building against
several opam roots/switches simultaneously. This helps maintaining
packages across several versions of OCaml and gives cross-compilation
for free.
"""
maintainer: ["Jane Street Group, LLC <opensource@janestreet.com>"]
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
license: "MIT"
homepage: "https://github.com/ocaml/dune"
doc: "https://dune.readthedocs.io/"
bug-reports: "https://github.com/ocaml/dune/issues"
conflicts: [
"merlin" {< "3.4.0"}
"ocaml-lsp-server" {< "1.3.0"}
"dune-configurator" {< "2.3.0"}
"odoc" {< "1.3.0"}
"dune-release" {< "1.3.0"}
"js_of_ocaml-compiler" {< "3.6.0"}
"jbuilder" {= "transition"}
]
dev-repo: "git+https://github.com/ocaml/dune.git"
build: [
# opam 2 sets OPAM_SWITCH_PREFIX, so we don't need a hardcoded path
["ocaml" "configure.ml" "--libdir" lib] {opam-version < "2"}
["ocaml" "bootstrap.ml" "-j" jobs]
["./dune.exe" "build" "-p" name "--profile" "dune-bootstrap" "-j" jobs]
]
depends: [
# Please keep the lower bound in sync with .github/workflows/workflow.yml,
# dune-project and min_ocaml_version in bootstrap.ml
("ocaml" {>= "4.08"} | ("ocaml" {< "4.08~~"} & "ocamlfind-secondary"))
"base-unix"
"base-threads"
]
x-commit-hash: "b6a3f66fb15378fc7170e94778f4d2c0b142ad92"
url {
src: "https://github.com/ocaml/dune/releases/download/2.8.4/dune-2.8.4.tbz"
checksum: [
"sha256=4e6420177584aabdc3b7b37aee3026b094b82bf5d7ed175344a68e321f72e8ac"
"sha512=efc1834c4add40138a101734665a1f462c19fe76d1cbb457b1fc20f95991118a50b24d485fb98d39046e41bec03885a8dc071bf8add51083ac9780bff9f6668a"
]
}
opam-version: "2.0"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
["dune" "build" "-p" name "@doc"] {with-doc}
]
maintainer: ["martin@mjambon.com" "rudi.grinberg@gmail.com"]
authors: ["Martin Jambon"]
bug-reports: "https://github.com/mjambon/easy-format/issues"
homepage: "https://github.com/mjambon/easy-format"
doc: "https://mjambon.github.io/easy-format/"
license: "BSD-3-Clause"
dev-repo: "git+https://github.com/mjambon/easy-format.git"
synopsis:
"High-level and functional interface to the Format module of the OCaml standard library"
description: """
This module offers a high-level and functional interface to the Format module of
the OCaml standard library. It is a pretty-printing facility, i.e. it takes as
input some code represented as a tree and formats this code into the most
visually satisfying result, breaking and indenting lines of code where
appropriate.
Input data must be first modelled and converted into a tree using 3 kinds of
nodes:
* atoms
* lists
* labelled nodes
Atoms represent any text that is guaranteed to be printed as-is. Lists can model
any sequence of items such as arrays of data or lists of definitions that are
labelled with something like "int main", "let x =" or "x:"."""
depends: [
"dune" {>= "1.10"}
"ocaml" {>= "4.02.3"}
]
url {
src:
"https://github.com/mjambon/easy-format/releases/download/1.3.2/easy-format-1.3.2.tbz"
checksum: [
"sha256=3440c2b882d537ae5e9011eb06abb53f5667e651ea4bb3b460ea8230fa8c1926"
"sha512=e39377a2ff020ceb9ac29e8515a89d9bdbc91dfcfa871c4e3baafa56753fac2896768e5d9822a050dc1e2ade43c8967afb69391a386c0a8ecd4e1f774e236135"
]
}
opam-version: "2.0"
maintainer: "francois.pottier@inria.fr"
authors: [
"François Pottier <francois.pottier@inria.fr>"
]
homepage: "https://gitlab.inria.fr/fpottier/fix"
dev-repo: "git+https://gitlab.inria.fr/fpottier/fix.git"
bug-reports: "francois.pottier@inria.fr"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" { >= "4.03" }
"dune" {>= "1.3" }
]
synopsis: "Facilities for memoization and fixed points"
url {
src:
"https://gitlab.inria.fr/fpottier/fix/repository/20201120/archive.tar.gz"
checksum: [
"md5=7eb570b759635fe66f3556d2b1cc88e3"
"sha512=344dcc619f9e8b8a6c998775b6d2dab2ea5253e6a67abe4797f76dc5dd30bc776568abce1e90477422e9db447821579889737e3531c42139708f813e983ea5d4"
]
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: ["The fpath programmers"]
homepage: "https://erratique.ch/software/fpath"
doc: "https://erratique.ch/software/fpath/doc"
dev-repo: "git+https://erratique.ch/repos/fpath.git"
bug-reports: "https://github.com/dbuenzli/fpath/issues"
tags: [ "file" "system" "path" "org:erratique" ]
license: "ISC"
depends: [
"ocaml" {>= "4.03.0"}
"ocamlfind" {build}
"ocamlbuild" {build}
"topkg" {build & >= "0.9.0"}
"astring"
]
build: [[
"ocaml" "pkg/pkg.ml" "build"
"--dev-pkg=true" {dev} ]]
synopsis: """File system paths for OCaml"""
description: """\
Fpath is an OCaml module for handling file system paths with POSIX or
Windows conventions. Fpath processes paths without accessing the file
system and is independent from any system library.
Fpath depends on [Astring][astring] and is distributed under the ISC
license.
[astring]: http://erratique.ch/software/astring
"""
url {
archive: "https://erratique.ch/software/fpath/releases/fpath-0.7.3.tbz"
checksum: "0740b530e8fed5b0adc5eee8463cfc2f"
}
opam-version: "2.0"
maintainer: "yallop@gmail.com"
authors: ["Jeremy Yallop"
"Demi Obenour"
"Stephane Glondu"
"Andreas Hauptmann"]
homepage: "https://github.com/ocamllabs/ocaml-integers"
bug-reports: "https://github.com/ocamllabs/ocaml-integers/issues"
dev-repo: "git+https://github.com/ocamllabs/ocaml-integers.git"
license: "MIT"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
depends: [
"ocaml" {>= "4.02"}
"dune"
]
doc: "http://ocamllabs.github.io/ocaml-integers/api.docdir/"
synopsis: "Various signed and unsigned integer types for OCaml"
url {
src: "https://github.com/ocamllabs/ocaml-integers/archive/0.4.0.tar.gz"
checksum: "md5=c1492352e6525048790508c57aad93c3"
}
opam-version: "2.0"
maintainer: "francois.pottier@inria.fr"
authors: [
"François Pottier <francois.pottier@inria.fr>"
"Yann Régis-Gianas <yrg@pps.univ-paris-diderot.fr>"
]
homepage: "http://gitlab.inria.fr/fpottier/menhir"
dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git"
bug-reports: "menhir@inria.fr"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.02.3"}
"dune" { >= "2.2.0"}
"menhirLib" {= version}
"menhirSdk" {= version}
]
synopsis: "An LR(1) parser generator"
url {
src:
"https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz"
checksum: [
"md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f"
]
}
opam-version: "2.0"
maintainer: "francois.pottier@inria.fr"
authors: [
"François Pottier <francois.pottier@inria.fr>"
"Yann Régis-Gianas <yrg@pps.univ-paris-diderot.fr>"
]
homepage: "http://gitlab.inria.fr/fpottier/menhir"
dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git"
bug-reports: "menhir@inria.fr"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" { >= "4.02.3" }
"dune" { >= "2.0.0" }
]
conflicts: [
"menhir" { != version }
]
synopsis: "Runtime support library for parsers generated by Menhir"
url {
src:
"https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz"
checksum: [
"md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f"
]
}
opam-version: "2.0"
maintainer: "francois.pottier@inria.fr"
authors: [
"François Pottier <francois.pottier@inria.fr>"
"Yann Régis-Gianas <yrg@pps.univ-paris-diderot.fr>"
]
homepage: "http://gitlab.inria.fr/fpottier/menhir"
dev-repo: "git+https://gitlab.inria.fr/fpottier/menhir.git"
bug-reports: "menhir@inria.fr"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" { >= "4.02.3" }
"dune" { >= "2.0.0" }
]
conflicts: [
"menhir" { != version }
]
synopsis: "Compile-time library for auxiliary tools related to Menhir"
url {
src:
"https://gitlab.inria.fr/fpottier/menhir/repository/20210310/archive.tar.gz"
checksum: [
"md5=1cbc71c0bc1f3ddc3e71d5c1f919fd1a"
"sha512=3c309fa2cc4ad7c6fba85107bd946a542894882fa39741496b150307e93455b717418f19e94b5dad06ab269f5c55e8dc25705c96c0a5092e623fa38f1ce43c7f"
]
}
opam-version: "2.0"
maintainer: "defree@gmail.com"
authors: "The Merlin team"
homepage: "https://github.com/ocaml/merlin"
bug-reports: "https://github.com/ocaml/merlin/issues"
dev-repo: "git+https://github.com/ocaml/merlin.git"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" "merlin,dot-merlin-reader" "-j" "1"] {with-test}
]
depends: [
"ocaml" {>= "4.11" & < "4.12"}
"dune" {>= "2.7.0"}
"dot-merlin-reader" {>= "4.0"}
"yojson" {>= "1.6.0"}
"conf-jq" {with-test}
"csexp" {>= "1.2.3"}
"result" {>= "1.5"}
"menhir" {dev}
"menhirLib" {dev}
"menhirSdk" {dev}
]
synopsis:
"Editor helper, provides completion, typing and source browsing in Vim and Emacs"
description:
"Merlin is an assistant for editing OCaml code. It aims to provide the features available in modern IDEs: error reporting, auto completion, source browsing and much more."
post-messages: [
"merlin installed.
Quick setup for VIM
-------------------
Append this to your .vimrc to add merlin to vim's runtime-path:
let g:opamshare = substitute(system('opam var share'),'\\n$','','''')
execute \"set rtp+=\" . g:opamshare . \"/merlin/vim\"
Also run the following line in vim to index the documentation:
:execute \"helptags \" . g:opamshare . \"/merlin/vim/doc\"
Quick setup for EMACS
-------------------
Add opam emacs directory to your load-path by appending this to your .emacs:
(let ((opam-share (ignore-errors (car (process-lines \"opam\" \"config\" \"var\" \"share\")))))
(when (and opam-share (file-directory-p opam-share))
;; Register Merlin
(add-to-list 'load-path (expand-file-name \"emacs/site-lisp\" opam-share))
(autoload 'merlin-mode \"merlin\" nil t nil)
;; Automatically start it in OCaml buffers
(add-hook 'tuareg-mode-hook 'merlin-mode t)
(add-hook 'caml-mode-hook 'merlin-mode t)
;; Use opam switch to lookup ocamlmerlin binary
(setq merlin-command 'opam)))
Take a look at https://github.com/ocaml/merlin for more information
Quick setup with opam-user-setup
--------------------------------
Opam-user-setup support Merlin.
$ opam user-setup install
should take care of basic setup.
See https://github.com/OCamlPro/opam-user-setup
"
{success & !user-setup:installed}
]
x-commit-hash: "0916b10c76025f7cb0855c67324f72e344046d77"
url {
src:
"https://github.com/ocaml/merlin/releases/download/v4.1-411/merlin-v4.1-411.tbz"
checksum: [
"sha256=9e2e6fc799c93ce1f2c7181645eafa37f64e43ace062b69218e1c29ac459937d"
"sha512=6a2e2503d81b22b0cc292ca6853231e59c42a216acec0cb540d03791d201fe83641a3502e62660668ad5d30405698e2429efe072cfd38dc30229024267f7c0b8"
]
}
opam-version: "2.0"
synopsis:
"The legacy Num library for arbitrary-precision integer and rational arithmetic"
maintainer: "Xavier Leroy <xavier.leroy@inria.fr>"
authors: ["Valérie Ménissier-Morain" "Pierre Weis" "Xavier Leroy"]
license: "LGPL-2.1-only with OCaml-LGPL-linking-exception"
homepage: "https://github.com/ocaml/num/"
bug-reports: "https://github.com/ocaml/num/issues"
depends: [
"ocaml" {>= "4.06.0"}
"ocamlfind" {build & >= "1.7.3"}
]
conflicts: ["base-num"]
build: make
install: [
make
"install" {!ocaml:preinstalled}
"findlib-install" {ocaml:preinstalled}
]
dev-repo: "git+https://github.com/ocaml/num.git"
url {
src: "https://github.com/ocaml/num/archive/v1.4.tar.gz"
checksum: [
"md5=cda2b727e116a0b6a9c03902cc4b2415"
"sha512=0cc9be8ad95704bb683b4bf6698bada1ee9a40dc05924b72adc7b969685c33eeb68ccf174cc09f6a228c48c18fe94af06f28bebc086a24973a066da620db8e6f"
]
}
opam-version: "2.0"
maintainer: "opensource@janestreet.com"
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
homepage: "https://github.com/janestreet/ocaml-compiler-libs"
bug-reports: "https://github.com/janestreet/ocaml-compiler-libs/issues"
dev-repo: "git+https://github.com/janestreet/ocaml-compiler-libs.git"
license: "MIT"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.04.1"}
"dune" {>= "1.5.1"}
]
synopsis: """OCaml compiler libraries repackaged"""
description: """
This packages exposes the OCaml compiler libraries repackages under
the toplevel names Ocaml_common, Ocaml_bytecomp, Ocaml_optcomp, ...
"""
x-commit-hash: "7f5d1d2931b96fb3ee6dd569a469b51f621a6dd4"
url {
src:
"https://github.com/janestreet/ocaml-compiler-libs/releases/download/v0.12.3/ocaml-compiler-libs-v0.12.3.tbz"
checksum: [
"sha256=a8403531439c14bbda2d504ef93610fd29a8e9520fc700f21889d893a513e3c9"
"sha512=0bb03b38e93bab3274a8ade38d017808110bc02f2181a594d8775c68fdd465733393f0451dbbf8860e6b50b56c45671d2182637c0840d1d6574803ec18673972"
]
}
opam-version: "2.0"
synopsis: "LSP Server for OCaml"
description: "An LSP server for OCaml."
maintainer: ["Rudi Grinberg <me@rgrinerg.com>"]
authors: [
"Andrey Popp <8mayday@gmail.com>"
"Rusty Key <iam@stfoo.ru>"
"Louis Roché <louis@louisroche.net>"
"Oleksiy Golovko <alexei.golovko@gmail.com>"
"Rudi Grinberg <me@rgrinberg.com>"
"Sacha Ayoun <sachaayoun@gmail.com>"
"cannorin <cannorin@gmail.com>"
]
license: "ISC"
homepage: "https://github.com/ocaml/ocaml-lsp"
bug-reports: "https://github.com/ocaml/ocaml-lsp/issues"
depends: [
"dune" {>= "2.5"}
"yojson"
"stdlib-shims"
"ppx_yojson_conv_lib"
"dune-build-info"
"dot-merlin-reader"
"csexp" {>= "1.2.3"}
"result" {>= "1.5"}
"ocamlformat" {with-test}
"ocamlfind" {>= "1.5.2"}
"odoc" {with-doc}
"ocaml" {>= "4.06" & < "4.12"}
]
dev-repo: "git+https://github.com/ocaml/ocaml-lsp.git"
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-j"
jobs
"ocaml-lsp-server.install"
"--release"
]
]
x-commit-hash: "154ccd7142651807d40eb851969f318b873b7fb4"
url {
src:
"https://github.com/ocaml/ocaml-lsp/releases/download/1.4.1/jsonrpc-1.4.1.tbz"
checksum: [
"sha256=cee8371e7048e24c90e916c373ef6f3aba6f474d8a5fcf507ab6650fd8575eeb"
"sha512=150ebf71d3484d3beec1a145877cf30d84581bd072dd20159e878ed07cc4fc647b019b98bb0c9fede839b87f7bd13de4a64b534c0760a2ec57d0e4a4deac6f0f"
]
}
opam-version: "2.0"
maintainer: "frederic.bour@lakaban.net"
authors: [
"Frédéric Bour <frederic.bour@lakaban.net>"
"Jérémie Dimino <jeremie@dimino.org>"
]
license: "LGPL-2.1 with OCaml linking exception"
homepage: "https://github.com/ocaml-ppx/ocaml-migrate-parsetree"
bug-reports: "https://github.com/ocaml-ppx/ocaml-migrate-parsetree/issues"
dev-repo: "git+https://github.com/ocaml-ppx/ocaml-migrate-parsetree.git"
doc: "https://ocaml-ppx.github.io/ocaml-migrate-parsetree/"
tags: [ "syntax" "org:ocamllabs" ]
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"dune" {>= "1.11"}
"ocaml" {>= "4.02.3" & < "4.13"}
]
synopsis: "Convert OCaml parsetrees between different versions"
description: """
Convert OCaml parsetrees between different versions
This library converts parsetrees, outcometree and ast mappers between
different OCaml versions. High-level functions help making PPX
rewriters independent of a compiler version.
"""
x-commit-hash: "4a05cf7a00d84e5f827cc9ae9c75e5dc85126085"
url {
src:
"https://github.com/ocaml-ppx/ocaml-migrate-parsetree/releases/download/v2.1.0/ocaml-migrate-parsetree-v2.1.0.tbz"
checksum: [
"sha256=387b788ee4c0537f1fe02c25e05f0335af424828fc6fe940acc0db5948a5a71f"
"sha512=6ac80face6b77531c8d89a77d7a246bd5d43da435c355f62c03c8b8e360e1d7e339c904709fd3dbc9aa340c86ada9a69d5ebcf97cbdb7bd51bec97f831741b99"
]
}
opam-version: "2.0"
maintainer: "Anil Madhavapeddy <anil@recoil.org>"
authors: "Anil Madhavapeddy <anil@recoil.org>"
license: "ISC"
tags: "org:ocamllabs"
homepage: "https://github.com/ocurrent/ocaml-version"
doc: "https://ocurrent.github.io/ocaml-version/doc"
bug-reports: "https://github.com/ocurrent/ocaml-version/issues"
depends: [
"ocaml" {>= "4.07.0"}
"dune"
"alcotest" {with-test}
]
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
]
dev-repo: "git+https://github.com/ocurrent/ocaml-version.git"
synopsis: "Manipulate, parse and generate OCaml compiler version strings"
description: """
This library provides facilities to parse version numbers of the OCaml
compiler, and enumerates the various official OCaml releases and configuration
variants.
OCaml version numbers are of the form `major.minor.patch+extra`, where the
`patch` and `extra` fields are optional. This library offers the following
functionality:
- Functions to parse and serialise OCaml compiler version numbers.
- Enumeration of official OCaml compiler version releases.
- Test compiler versions for a particular feature (e.g. the `bytes` type)
- [opam](https://opam.ocaml.org) compiler switch enumeration.
### Further information
- **Discussion:** Post on <https://discuss.ocaml.org/> with the `ocaml` tag under
the Ecosystem category.
- **Bugs:** <https://github.com/ocurrent/ocaml-version/issues>
- **Docs:** <http://docs.mirage.io/ocaml-version>
"""
x-commit-hash: "eb14804dbf9424c27c8d14fce19b3243f80a69fa"
url {
src:
"https://github.com/ocurrent/ocaml-version/releases/download/v3.1.0/ocaml-version-v3.1.0.tbz"
checksum: [
"sha256=ac7ba16a09d8f72212742f3936980fbfaebb698c7bbf625182af7d6b2c3cde5f"
"sha512=6e11823531f1f70b5d4b90ed9f2fcc22cbf83924a7a0ef40eebc4b80598db6acdaca97f1d379e01860513d5dda492f5bc4d944f0c1dd7df491b2f36a0f729bb5"
]
}
opam-version: "2.0"
maintainer: "Gabriel Scherer <gabriel.scherer@gmail.com>"
authors: ["Nicolas Pouillard" "Berke Durak"]
homepage: "https://github.com/ocaml/ocamlbuild/"
bug-reports: "https://github.com/ocaml/ocamlbuild/issues"
license: "LGPL-2.1-only with OCaml-LGPL-linking-exception"
doc: "https://github.com/ocaml/ocamlbuild/blob/master/manual/manual.adoc"
dev-repo: "git+https://github.com/ocaml/ocamlbuild.git"
build: [
[
make
"-f"
"configure.make"
"all"
"OCAMLBUILD_PREFIX=%{prefix}%"
"OCAMLBUILD_BINDIR=%{bin}%"
"OCAMLBUILD_LIBDIR=%{lib}%"
"OCAMLBUILD_MANDIR=%{man}%"
"OCAML_NATIVE=%{ocaml:native}%"
"OCAML_NATIVE_TOOLS=%{ocaml:native}%"
]
[make "check-if-preinstalled" "all" "opam-install"]
]
conflicts: [
"base-ocamlbuild"
"ocamlfind" {< "1.6.2"}
]
synopsis:
"OCamlbuild is a build system with builtin rules to easily build most OCaml projects."
depends: [
"ocaml" {>= "4.03"}
]
url {
src: "https://github.com/ocaml/ocamlbuild/archive/0.14.0.tar.gz"
checksum: "sha256=87b29ce96958096c0a1a8eeafeb6268077b2d11e1bf2b3de0f5ebc9cf8d42e78"
}
#!/bin/sh
BINDIR=$(dirname "$(command -v ocamlc)")
"$BINDIR/ocaml" -I "$OCAML_TOPLEVEL_PATH" "$@"
bin: [
"src/findlib/ocamlfind" {"ocamlfind"}
"?src/findlib/ocamlfind_opt" {"ocamlfind"}
"?tools/safe_camlp4"
]
toplevel: ["src/findlib/topfind"]
opam-version: "2.0"
synopsis: "A library manager for OCaml"
maintainer: "Thomas Gazagnaire <thomas@gazagnaire.org>"
authors: "Gerd Stolpmann <gerd@gerd-stolpmann.de>"
homepage: "http://projects.camlcity.org/projects/findlib.html"
bug-reports: "https://gitlab.camlcity.org/gerd/lib-findlib/issues"
dev-repo: "git+https://gitlab.camlcity.org/gerd/lib-findlib.git"
description: """
Findlib is a library manager for OCaml. It provides a convention how
to store libraries, and a file format ("META") to describe the
properties of libraries. There is also a tool (ocamlfind) for
interpreting the META files, so that it is very easy to use libraries
in programs and scripts.
"""
build: [
[
"./configure"
"-bindir"
bin
"-sitelib"
lib
"-mandir"
man
"-config"
"%{lib}%/findlib.conf"
"-no-custom"
"-no-camlp4" {!ocaml:preinstalled & ocaml:version >= "4.02.0"}
"-no-topfind" {ocaml:preinstalled}
]
[make "all"]
[make "opt"] {ocaml:native}
]
install: [
[
"./configure"
"-bindir"
bin
"-sitelib"
lib
"-mandir"
man
"-config"
"%{lib}%/findlib.conf"
"-no-custom"
"-no-camlp4" {!ocaml:preinstalled & ocaml:version >= "4.02.0"}
"-no-topfind" {ocaml:preinstalled}
]
[make "install"]
["install" "-m" "0755" "ocaml-stub" "%{bin}%/ocaml"] {ocaml:preinstalled}
]
depends: [
"ocaml" {>= "4.00.0" & < "4.13"}
"conf-m4" {build}
]
extra-files: [
["ocamlfind.install" "md5=06f2c282ab52d93aa6adeeadd82a2543"]
["ocaml-stub" "md5=181f259c9e0bad9ef523e7d4abfdf87a"]
]
url {
src: "http://download.camlcity.org/download/findlib-1.8.1.tar.gz"
checksum: "md5=18ca650982c15536616dea0e422cbd8c"
mirrors: "http://download2.camlcity.org/download/findlib-1.8.1.tar.gz"
}
depopts: ["graphics"]
opam-version: "2.0"
synopsis: "Auto-formatter for OCaml code"
description:
"OCamlFormat is a tool to automatically format OCaml code in a uniform style."
maintainer: ["OCamlFormat Team <ocamlformat-team@fb.com>"]
authors: ["Josh Berdine <jjb@fb.com>"]
license: "MIT"
homepage: "https://github.com/ocaml-ppx/ocamlformat"
bug-reports: "https://github.com/ocaml-ppx/ocamlformat/issues"
depends: [
"dune" {>= "2.7"}
"ocaml" {>= "4.08" & < "4.13"}
"ocaml-version"
"alcotest" {with-test}
"base" {>= "v0.12.0" & < "v0.15"}
"base-unix"
"cmdliner"
"dune-build-info"
"fix"
"fpath"
"menhir" {>= "20180528"}
"menhirLib" {>= "20200624"}
"menhirSdk" {>= "20200624"}
"ocaml-migrate-parsetree" {>= "2.1.0"}
"ocp-indent" {with-test}
"odoc" {>= "1.4.2"}
"ppxlib" {>= "0.22.0"}
"re"
"stdio" {< "v0.15"}
"uuseg" {>= "10.0.0"}
"uutf" {>= "1.0.1"}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/ocaml-ppx/ocamlformat.git"
x-commit-hash: "bfd6bbe95c614d1d982244c4fd0ba494275d2245"
url {
src:
"https://github.com/ocaml-ppx/ocamlformat/releases/download/0.17.0/ocamlformat-0.17.0.tbz"
checksum: [
"sha256=68848b12e82dc1077a29f63d2777680e692b1a565276fcd00f06fb93cced3438"
"sha512=168ac7dee5a78954b273972b099681a4f2a6864b81c1dfe5ee5ff2f0ba79f150aeca8128b95dce4fd30d4d830906f02975d56b804dbb513fe0bb63c95d61030b"
]
}
opam-version: "2.0"
homepage: "http://github.com/ocaml/odoc"
doc: "https://ocaml.github.io/odoc/"
bug-reports: "https://github.com/ocaml/odoc/issues"
license: "ISC"
authors: [
"Thomas Refis <trefis@janestreet.com>"
"David Sheets <sheets@alum.mit.edu>"
"Leo White <leo@lpw25.net>"
"Anton Bachin <antonbachin@yahoo.com>"
"Jon Ludlam <jon@recoil.org>"
]
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
dev-repo: "git+https://github.com/ocaml/odoc.git"
synopsis: "OCaml documentation generator"
description: """
Odoc is a documentation generator for OCaml. It reads doc comments,
delimited with `(** ... *)`, and outputs HTML.
"""
depends: [
"astring"
"cmdliner"
"cppo" {build}
"dune"
"fpath"
"ocaml" {>= "4.02.0" & < "4.13"}
"result"
"tyxml" {>= "4.3.0"}
"alcotest" {dev & >= "0.8.3"}
"markup" {dev & >= "1.0.0"}
"ocamlfind" {dev}
"sexplib" {dev & >= "113.33.00"}
"bisect_ppx" {dev & >= "1.3.0"}
]
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
]
x-commit-hash: "c0df8ce2171fa9645a41f371429aa3ddc16de5c1"
url {
src: "https://github.com/ocaml/odoc/releases/download/1.5.2/odoc-1.5.2.tbz"
checksum: [
"sha256=d24463f2660bc28c72cda001478360158e953721c9e23fb361ec4783113c4871"
"sha512=e6c83630325de422f31cda8f88c038d213969f8b98e989593c057658f3956c0855860c9bc38f61b6479929516ca95aee689ddfba3ad8c47d821c4fdf54524cf9"
]
}
opam-version: "2.0"
maintainer: "andreashauptmann@t-online.de"
authors: [ "andreashauptmann@t-online.de" ]
license: "LGPL-2.1-or-later with OCaml-LGPL-linking-exception"
homepage: "https://fdopen.github.io/ppx_cstubs/"
dev-repo: "git+https://github.com/fdopen/ppx_cstubs.git"
doc: "https://fdopen.github.io/ppx_cstubs/"
bug-reports: "https://github.com/fdopen/ppx_cstubs/issues"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"bigarray-compat"
"ctypes" {>= "0.13.0" & < "0.19"}
"integers"
"num"
"result"
"containers" {>= "2.2"}
"cppo" {build & >= "1.3"}
"ocaml" {>= "4.04.2" & < "4.13.0"}
"ppxlib" {>= "0.22.0"}
"ocamlfind" {>= "1.7.2"} # not only a build dependency, it depends on findlib.top
"dune" {>= "1.6"}
"re" {>= "1.7.2"}
]
synopsis: """
Preprocessor for easier stub generation with ctypes
"""
description: """
ppx_cstubs is a ppx-based preprocessor for stub generation with
ctypes. ppx_cstubs creates two files from a single ml file: a file
with c stub code and an OCaml file with all additional boilerplate
code.
"""
url {
src: "https://github.com/fdopen/ppx_cstubs/archive/0.6.1.1.tar.gz"
checksum: [
"md5=33e520e369da5630c697318f6f4ed26d"
"sha512=77f28fd93ba476ccad089029fb7c7254a4525ea2d61f4d0a74c69b8c771e2657929c16cfa334671ccead1c02743804fc3db7726fd3e47772f50dc4a16270435c"
]
}
opam-version: "2.0"
maintainer: "jeremie@dimino.org"
authors: ["Jérémie Dimino"]
license: "BSD-3-Clause"
homepage: "https://github.com/ocaml-ppx/ppx_derivers"
bug-reports: "https://github.com/ocaml-ppx/ppx_derivers/issues"
dev-repo: "git://github.com/ocaml-ppx/ppx_derivers.git"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml"
"dune"
]
synopsis: "Shared [@@deriving] plugin registry"
description: """
Ppx_derivers is a tiny package whose sole purpose is to allow
ppx_deriving and ppx_type_conv to inter-operate gracefully when linked
as part of the same ocaml-migrate-parsetree driver."""
url {
src: "https://github.com/ocaml-ppx/ppx_derivers/archive/1.2.1.tar.gz"
checksum: "md5=5dc2bf130c1db3c731fe0fffc5648b41"
}
opam-version: "2.0"
maintainer: "opensource@janestreet.com"
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
homepage: "https://github.com/janestreet/ppx_yojson_conv_lib"
bug-reports: "https://github.com/janestreet/ppx_yojson_conv_lib/issues"
dev-repo: "git+https://github.com/janestreet/ppx_yojson_conv_lib.git"
doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/ppx_yojson_conv_lib/index.html"
license: "MIT"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.02.3"}
"dune" {>= "2.0.0"}
"yojson" {>= "1.7.0"}
]
synopsis: "Runtime lib for ppx_yojson_conv"
description: "
Part of the Jane Street's PPX rewriters collection.
"
url {
src: "https://ocaml.janestreet.com/ocaml-core/v0.14/files/ppx_yojson_conv_lib-v0.14.0.tar.gz"
checksum: "md5=e23c5593a7211ad4fb09e26e9a74698a"
}
opam-version: "2.0"
synopsis: "Standard library for ppx rewriters"
description: """
Ppxlib is the standard library for ppx rewriters and other programs
that manipulate the in-memory reprensation of OCaml programs, a.k.a
the "Parsetree".
It also comes bundled with two ppx rewriters that are commonly used to
write tools that manipulate and/or generate Parsetree values;
`ppxlib.metaquot` which allows to construct Parsetree values using the
OCaml syntax directly and `ppxlib.traverse` which provides various
ways of automatically traversing values of a given type, in particular
allowing to inject a complex structured value into generated code.
"""
maintainer: ["opensource@janestreet.com"]
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
license: "MIT"
homepage: "https://github.com/ocaml-ppx/ppxlib"
doc: "https://ocaml-ppx.github.io/ppxlib/"
bug-reports: "https://github.com/ocaml-ppx/ppxlib/issues"
depends: [
"dune" {>= "2.7"}
"ocaml" {>= "4.04.1" & < "4.13"}
"ocaml-compiler-libs" {>= "v0.11.0"}
"ocaml-migrate-parsetree" {>= "2.1.0"}
"ppx_derivers" {>= "1.0"}
"sexplib0"
"stdlib-shims"
"ocamlfind" {with-test}
"re" {with-test & >= "1.9.0"}
"cinaps" {with-test & >= "v0.12.1"}
"base" {with-test}
"stdio" {with-test}
"odoc" {with-doc}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/ocaml-ppx/ppxlib.git"
x-commit-hash: "06a2c9bdad8c1d3361a3d9430e9bf58476b08590"
url {
src:
"https://github.com/ocaml-ppx/ppxlib/releases/download/0.22.0/ppxlib-0.22.0.tbz"
checksum: [
"sha256=3eeb91e03966662284a3222e612dee7f4fa2b7637c53d9572d2a74134bb96d7a"
"sha512=425051dff9df53579a6edd17369d66c10f87a78daeddf1691e50997990ed643e874fcc6a30112a4dacbfd2d0097a19445354e04cd920d9522f76c51cdbc7f1db"
]
}
opam-version: "2.0"
maintainer: "rudi.grinberg@gmail.com"
authors: [
"Jerome Vouillon"
"Thomas Gazagnaire"
"Anil Madhavapeddy"
"Rudi Grinberg"
"Gabriel Radanne"
]
license: "LGPL-2.0-only with OCaml-LGPL-linking-exception"
homepage: "https://github.com/ocaml/ocaml-re"
bug-reports: "https://github.com/ocaml/ocaml-re/issues"
dev-repo: "git+https://github.com/ocaml/ocaml-re.git"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
depends: [
"ocaml" {>= "4.02"}
"dune"
"ounit" {with-test}
"seq"
]
synopsis: "RE is a regular expression library for OCaml"
description: """
Pure OCaml regular expressions with:
* Perl-style regular expressions (module Re.Perl)
* Posix extended regular expressions (module Re.Posix)
* Emacs-style regular expressions (module Re.Emacs)
* Shell-style file globbing (module Re.Glob)
* Compatibility layer for OCaml's built-in Str module (module Re.Str)
"""
url {
src:
"https://github.com/ocaml/ocaml-re/releases/download/1.9.0/re-1.9.0.tbz"
checksum: "md5=bddaed4f386a22cace7850c9c7dac296"
}
opam-version: "2.0"
maintainer: "opensource@janestreet.com"
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
homepage: "https://github.com/janestreet/result"
dev-repo: "git+https://github.com/janestreet/result.git"
bug-reports: "https://github.com/janestreet/result/issues"
license: "BSD-3-Clause"
build: [["dune" "build" "-p" name "-j" jobs]]
depends: [
"ocaml"
"dune" {>= "1.0"}
]
synopsis: "Compatibility Result module"
description: """
Projects that want to use the new result type defined in OCaml >= 4.03
while staying compatible with older version of OCaml should use the
Result module defined in this library."""
url {
src:
"https://github.com/janestreet/result/releases/download/1.5/result-1.5.tbz"
checksum: "md5=1b82dec78849680b49ae9a8a365b831b"
}
name="seq"
version="[distributed with OCaml 4.07 or above]"
description="dummy backward-compatibility package for iterators"
requires=""
lib:[
"META.seq" {"META"}
]
opam-version: "2.0"
maintainer: " "
authors: " "
homepage: " "
depends: [
"ocaml" {>= "4.07.0"}
]
dev-repo: "git+https://github.com/ocaml/ocaml.git"
bug-reports: "https://caml.inria.fr/mantis/main_page.php"
synopsis:
"Compatibility package for OCaml's standard iterator type starting from 4.07."
extra-files: [
["seq.install" "md5=026b31e1df290373198373d5aaa26e42"]
["META.seq" "md5=b33c8a1a6c7ed797816ce27df4855107"]
]
opam-version: "2.0"
maintainer: "opensource@janestreet.com"
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
homepage: "https://github.com/janestreet/sexplib0"
bug-reports: "https://github.com/janestreet/sexplib0/issues"
dev-repo: "git+https://github.com/janestreet/sexplib0.git"
doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/sexplib0/index.html"
license: "MIT"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.04.2"}
"dune" {>= "2.0.0"}
]
synopsis: "Library containing the definition of S-expressions and some base converters"
description: "
Part of Jane Street's Core library
The Core suite of libraries is an industrial strength alternative to
OCaml's standard library that was developed by Jane Street, the
largest industrial user of OCaml.
"
url {
src: "https://ocaml.janestreet.com/ocaml-core/v0.14/files/sexplib0-v0.14.0.tar.gz"
checksum: "md5=37aff0af8f8f6f759249475684aebdc4"
}
opam-version: "2.0"
maintainer: "opensource@janestreet.com"
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
homepage: "https://github.com/janestreet/stdio"
bug-reports: "https://github.com/janestreet/stdio/issues"
dev-repo: "git+https://github.com/janestreet/stdio.git"
doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/stdio/index.html"
license: "MIT"
build: [
["dune" "build" "-p" name "-j" jobs]
]
depends: [
"ocaml" {>= "4.04.2"}
"base" {>= "v0.14" & < "v0.15"}
"dune" {>= "2.0.0"}
]
synopsis: "Standard IO library for OCaml"
description: "
Stdio implements simple input/output functionalities for OCaml.
It re-exports the input/output functions of the OCaml standard
libraries using a more consistent API.
"
url {
src: "https://ocaml.janestreet.com/ocaml-core/v0.14/files/stdio-v0.14.0.tar.gz"
checksum: "md5=4cbdf15f0be88c3258aaeff9e04e00e9"
}
opam-version: "2.0"
maintainer: "The stdlib-shims programmers"
authors: "The stdlib-shims programmers"
homepage: "https://github.com/ocaml/stdlib-shims"
doc: "https://ocaml.github.io/stdlib-shims/"
dev-repo: "git+https://github.com/ocaml/stdlib-shims.git"
bug-reports: "https://github.com/ocaml/stdlib-shims/issues"
tags: ["stdlib" "compatibility" "org:ocaml"]
license: ["typeof OCaml system"]
depends: [
"dune"
"ocaml" {>= "4.02.3"}
]
build: [ "dune" "build" "-p" name "-j" jobs ]
synopsis: "Backport some of the new stdlib features to older compiler"
description: """
Backport some of the new stdlib features to older compiler,
such as the Stdlib module.
This allows projects that require compatibility with older compiler to
use these new features in their code.
"""
x-commit-hash: "fb6815e5d745f07fd567c11671149de6ef2e74c8"
url {
src:
"https://github.com/ocaml/stdlib-shims/releases/download/0.3.0/stdlib-shims-0.3.0.tbz"
checksum: [
"sha256=babf72d3917b86f707885f0c5528e36c63fccb698f4b46cf2bab5c7ccdd6d84a"
"sha512=1151d7edc8923516e9a36995a3f8938d323aaade759ad349ed15d6d8501db61ffbe63277e97c4d86149cf371306ac23df0f581ec7e02611f58335126e1870980"
]
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: ["Daniel Bünzli <daniel.buenzl i@erratique.ch>"]
homepage: "http://erratique.ch/software/topkg"
doc: "http://erratique.ch/software/topkg/doc"
license: "ISC"
dev-repo: "git+http://erratique.ch/repos/topkg.git"
bug-reports: "https://github.com/dbuenzli/topkg/issues"
tags: ["packaging" "ocamlbuild" "org:erratique"]
depends: [
"ocaml" {>= "4.03.0"}
"ocamlfind" {build & >= "1.6.1"}
"ocamlbuild" ]
build: [[
"ocaml" "pkg/pkg.ml" "build"
"--pkg-name" name
"--dev-pkg" "%{pinned}%" ]]
synopsis: """The transitory OCaml software packager"""
description: """\
Topkg is a packager for distributing OCaml software. It provides an
API to describe the files a package installs in a given build
configuration and to specify information about the package's
distribution, creation and publication procedures.
The optional topkg-care package provides the `topkg` command line tool
which helps with various aspects of a package's life cycle: creating
and linting a distribution, releasing it on the WWW, publish its
documentation, add it to the OCaml opam repository, etc.
Topkg is distributed under the ISC license and has **no**
dependencies. This is what your packages will need as a *build*
dependency.
Topkg-care is distributed under the ISC license it depends on
[fmt][fmt], [logs][logs], [bos][bos], [cmdliner][cmdliner],
[webbrowser][webbrowser] and `opam-format`.
[fmt]: http://erratique.ch/software/fmt
[logs]: http://erratique.ch/software/logs
[bos]: http://erratique.ch/software/bos
[cmdliner]: http://erratique.ch/software/cmdliner
[webbrowser]: http://erratique.ch/software/webbrowser
"""
url {
archive: "http://erratique.ch/software/topkg/releases/topkg-1.0.3.tbz"
checksum: "e285f7a296d77ee7d831ba9a6bfb396f"
}
opam-version: "2.0"
maintainer: "dev@ocsigen.org"
homepage: "https://github.com/ocsigen/tyxml/"
bug-reports: "https://github.com/ocsigen/tyxml/issues"
doc: "https://ocsigen.org/tyxml/manual/"
dev-repo: "git+https://github.com/ocsigen/tyxml.git"
license: "LGPL-2.1 with OCaml linking exception"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
depends: [
"ocaml" {>= "4.02"}
"dune"
"alcotest" {with-test}
"seq"
"uutf" {>= "1.0.0"}
"re" {>= "1.5.0"}
]
synopsis:"TyXML is a library for building correct HTML and SVG documents"
description:"""
TyXML provides a set of convenient combinators that uses the OCaml
type system to ensure the validity of the generated documents. TyXML
can be used with any representation of HTML and SVG: the textual one,
provided directly by this package, or DOM trees (`js_of_ocaml-tyxml`)
virtual DOM (`virtual-dom`) and reactive or replicated trees
(`eliom`). You can also create your own representation and use it to
instantiate a new set of combinators.
```ocaml
open Tyxml
let to_ocaml = Html.(a ~a:[a_href "ocaml.org"] [txt "OCaml!"])
```
"""
authors: "The ocsigen team"
url {
src:
"https://github.com/ocsigen/tyxml/releases/download/4.4.0/tyxml-4.4.0.tbz"
checksum: [
"sha256=516394dd4a5c31726997c51d66aa31cacb91e3c46d4e16c7699130e204042530"
"sha512=d5f2187f8410524cec7a14b28e8950837070eb0b6571b015dd06076c2841eb7ccaffa86d5d2307eaf1950ee62f9fb926477dac01c870d9c1a2f525853cb44d0c"
]
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: ["Daniel Bünzli <daniel.buenzl i@erratique.ch>"]
homepage: "http://ocaml.org"
doc: "https://ocaml.github.io/uchar/"
dev-repo: "git+https://github.com/ocaml/uchar.git"
bug-reports: "https://github.com/ocaml/uchar/issues"
tags: [ "text" "character" "unicode" "compatibility" "org:ocaml.org" ]
license: "typeof OCaml system"
depends: [
"ocaml" {>= "3.12.0"}
"ocamlbuild" {build}
]
build: [
["ocaml" "pkg/git.ml"]
[
"ocaml"
"pkg/build.ml"
"native=%{ocaml:native}%"
"native-dynlink=%{ocaml:native-dynlink}%"
]
]
synopsis: "Compatibility library for OCaml's Uchar module"
description: """
The `uchar` package provides a compatibility library for the
[`Uchar`][1] module introduced in OCaml 4.03.
The `uchar` package is distributed under the license of the OCaml
compiler. See [LICENSE](LICENSE) for details.
[1]: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Uchar.html"""
url {
src:
"https://github.com/ocaml/uchar/releases/download/v0.0.2/uchar-0.0.2.tbz"
checksum: "md5=c9ba2c738d264c420c642f7bb1cf4a36"
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: [ "The uucp programmers" ]
homepage: "https://erratique.ch/software/uucp"
doc: "https://erratique.ch/software/uucp/doc/Uucp"
dev-repo: "git+https://erratique.ch/repos/uucp.git"
bug-reports: "https://github.com/dbuenzli/uucp/issues"
tags: [ "unicode" "text" "character" "org:erratique" ]
license: "ISC"
depends: [
"ocaml" {>= "4.03.0"}
"ocamlfind" {build}
"ocamlbuild" {build}
"topkg" {build}
"uucd" {with-test} # dev really
"uunf" {with-test}
"uutf" {with-test}
]
depopts: [ "uunf" "uutf" "cmdliner" ]
conflicts: [ "uutf" {< "1.0.1"}
"cmdliner" {< "1.0.0"} ]
build: [[
"ocaml" "pkg/pkg.ml" "build"
"--dev-pkg" "%{pinned}%"
"--with-uutf" "%{uutf:installed}%"
"--with-uunf" "%{uunf:installed}%"
"--with-cmdliner" "%{cmdliner:installed}%"
]]
synopsis: """Unicode character properties for OCaml"""
description: """\
Uucp is an OCaml library providing efficient access to a selection of
character properties of the [Unicode character database][1].
Uucp is independent from any Unicode text data structure and has no
dependencies. It is distributed under the ISC license.
[1]: http://www.unicode.org/reports/tr44/
"""
url {
archive: "https://erratique.ch/software/uucp/releases/uucp-13.0.0.tbz"
checksum: "07e706249ddb2d02f0fa298804d3c739"
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: ["The uuseg programmers"]
homepage: "https://erratique.ch/software/uuseg"
doc: "https://erratique.ch/software/uuseg"
dev-repo: "git+https://erratique.ch/repos/uuseg.git"
bug-reports: "https://github.com/dbuenzli/uuseg/issues"
tags: [ "segmentation" "text" "unicode" "org:erratique" ]
license: "ISC"
depends: [ "ocaml" {>= "4.03.0"}
"ocamlfind" {build}
"ocamlbuild" {build}
"topkg" {build}
"uucp" {>= "13.0.0" & < "14.0.0"} ]
depopts: [ "uutf"
"cmdliner"
"uutf" {with-test}
"cmdliner" {with-test} ]
conflicts: [ "uutf" {< "1.0.0"} ]
build: [[
"ocaml" "pkg/pkg.ml" "build"
"--pinned" "%{pinned}%"
"--with-uutf" "%{uutf:installed}%"
"--with-cmdliner" "%{cmdliner:installed}%" ]]
synopsis: """Unicode text segmentation for OCaml"""
description: """\
Uuseg is an OCaml library for segmenting Unicode text. It implements
the locale independent [Unicode text segmentation algorithms][1] to
detect grapheme cluster, word and sentence boundaries and the
[Unicode line breaking algorithm][2] to detect line break
opportunities.
The library is independent from any IO mechanism or Unicode text data
structure and it can process text without a complete in-memory
representation.
Uuseg depends on [Uucp](http://erratique.ch/software/uucp) and
optionally on [Uutf](http://erratique.ch/software/uutf) for support on
OCaml UTF-X encoded strings. It is distributed under the ISC license.
[1]: http://www.unicode.org/reports/tr29/
[2]: http://www.unicode.org/reports/tr14/
"""
url {
archive: "https://erratique.ch/software/uuseg/releases/uuseg-13.0.0.tbz"
checksum: "a07a97fff61da604614ea8da0547ef6a"
}
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: ["Daniel Bünzli <daniel.buenzl i@erratique.ch>"]
homepage: "http://erratique.ch/software/uutf"
doc: "http://erratique.ch/software/uutf/doc/Uutf"
dev-repo: "git+http://erratique.ch/repos/uutf.git"
bug-reports: "https://github.com/dbuenzli/uutf/issues"
tags: [ "unicode" "text" "utf-8" "utf-16" "codec" "org:erratique" ]
license: "ISC"
depends: [
"ocaml" {>= "4.01.0"}
"ocamlfind" {build}
"ocamlbuild" {build}
"topkg" {build}
"uchar"
]
depopts: ["cmdliner"]
conflicts: ["cmdliner" { < "0.9.6"} ]
build: [[
"ocaml" "pkg/pkg.ml" "build"
"--pinned" "%{pinned}%"
"--with-cmdliner" "%{cmdliner:installed}%" ]]
synopsis: """Non-blocking streaming Unicode codec for OCaml"""
description: """\
Uutf is a non-blocking streaming codec to decode and encode the UTF-8,
UTF-16, UTF-16LE and UTF-16BE encoding schemes. It can efficiently
work character by character without blocking on IO. Decoders perform
character position tracking and support newline normalization.
Functions are also provided to fold over the characters of UTF encoded
OCaml string values and to directly encode characters in OCaml
Buffer.t values.
Uutf has no dependency and is distributed under the ISC license.
"""
url {
archive: "http://erratique.ch/software/uutf/releases/uutf-1.0.2.tbz"
checksum: "a7c542405a39630c689a82bd7ef2292c"
}
opam-version: "2.0"
maintainer: "martin@mjambon.com"
authors: ["Martin Jambon"]
homepage: "https://github.com/ocaml-community/yojson"
bug-reports: "https://github.com/ocaml-community/yojson/issues"
dev-repo: "git+https://github.com/ocaml-community/yojson.git"
doc: "https://ocaml-community.github.io/yojson/"
build: [
["dune" "subst"] {pinned}
["dune" "build" "-p" name "-j" jobs]
]
run-test: [["dune" "runtest" "-p" name "-j" jobs]]
depends: [
"ocaml" {>= "4.02.3"}
"dune"
"cppo" {build}
"easy-format"
"biniou" {>= "1.2.0"}
"alcotest" {with-test & >= "0.8.5"}
]
synopsis:
"Yojson is an optimized parsing and printing library for the JSON format"
description: """
Yojson is an optimized parsing and printing library for the JSON format.
It addresses a few shortcomings of json-wheel including 2x speedup,
polymorphic variants and optional syntax for tuples and variants.
ydump is a pretty-printing command-line program provided with the
yojson package.
The program atdgen can be used to derive OCaml-JSON serializers and
deserializers from type definitions."""
url {
src:
"https://github.com/ocaml-community/yojson/releases/download/1.7.0/yojson-1.7.0.tbz"
checksum: "md5=b89d39ca3f8c532abe5f547ad3b8f84d"
}
{
"build": "true",
"dependencies": {
"esy-libffi": "esy-ocaml/libffi#c61127dba57b18713039ab9c1892c9f2563e280c"
}
}
{
"build": "true",
"dependencies": {
"esy-m4": "esy-packages/esy-m4#c7cf0ac9221be2b1f9d90e83559ca08397a629e7"
}
}
{
"build": [
[
"pkg-config",
"--help"
]
],
"dependencies": {
"yarn-pkg-config": "esy-ocaml/yarn-pkg-config#db3a0b63883606dd57c54a7158d560d6cba8cd79"
}
}
{
"dependencies": {
"@esy-ocaml/libffi": "3.2.10"
}
}
{
"exportedEnv": {
"CAML_LD_LIBRARY_PATH": {
"val": "#{self.lib / 'ctypes' : $CAML_LD_LIBRARY_PATH}",
"scope": "global"
}
}
}
diff --git a/src/Makefile b/src/Makefile
index 8ad0e2c..d41d63c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,16 +1,16 @@
-OCAMLC=ocamlc
-OCAMLOPT=ocamlopt
-OCAMLDEP=ocamldep
-OCAMLMKLIB=ocamlmklib
-OCAMLFIND=ocamlfind
+OCAMLC=$(shell which ocamlc)
+OCAMLOPT=$(shell which ocamlopt)
+OCAMLDEP=$(shell which ocamldep)
+OCAMLMKLIB=$(shell which ocamlmklib)
+OCAMLFIND=$(shell which ocamlfind)
INSTALL_DATA=install -m 644
INSTALL_DLL=install
INSTALL_DIR=install -d
STDLIBDIR=$(shell $(OCAMLC) -where)
DESTDIR ?=
-include $(STDLIBDIR)/Makefile.config
+include $(STDLIBDIR)/Makefile.config
ifeq "$(filter i386 amd64 arm64 power,$(ARCH))" ""
# Unsupported architecture
BNG_ARCH=generic
@@ -86,14 +86,14 @@ endif
VERSION=$(shell sed -ne 's/^ *version *: *"\([^"]*\)".*$$/\1/p' ../num.opam)
install:
- $(INSTALL_DIR) $(DESTDIR)$(STDLIBDIR)
+ $(INSTALL_DIR) $(LIBDIR)
sed -e 's/%%VERSION%%/$(VERSION)/g' META.in > META
$(OCAMLFIND) install num META
rm -f META
- $(INSTALL_DATA) $(TOINSTALL) $(DESTDIR)$(STDLIBDIR)
+ $(INSTALL_DATA) $(TOINSTALL) $(LIBDIR)
ifeq "$(SUPPORTS_SHARED_LIBRARIES)" "true"
- $(INSTALL_DIR) $(DESTDIR)$(STDLIBDIR)/stublibs
- $(INSTALL_DLL) $(TOINSTALL_STUBS) $(DESTDIR)$(STDLIBDIR)/stublibs
+ $(INSTALL_DIR) $(LIBDIR)/stublibs
+ $(INSTALL_DLL) $(TOINSTALL_STUBS) $(LIBDIR)/stublibs
endif
findlib-install:
@@ -105,9 +105,9 @@ findlib-uninstall:
$(OCAMLFIND) remove num
uninstall: findlib-uninstall
- cd $(DESTDIR)$(STDLIBDIR) && rm -f $(TOINSTALL)
+ cd $(LIBDIR) && rm -f $(TOINSTALL)
ifeq "$(SUPPORTS_SHARED_LIBRARIES)" "true"
- cd $(DESTDIR)$(STDLIBDIR)/stublibs && rm -f $(TOINSTALL_STUBS)
+ cd $(LIBDIR)/stublibs && rm -f $(TOINSTALL_STUBS)
endif
clean:
{
"buildsInSource": true,
"build": [
[
"make"
]
],
"install": [
[
"make",
"LIBDIR=#{self.install / 'lib'}",
"findlib-install"
]
],
"exportedEnv": {
"CAML_LD_LIBRARY_PATH": {
"val": "#{self.install / 'lib' / 'num' : $CAML_LD_LIBRARY_PATH}",
"scope": "global"
}
},
"dependencies": {
"ocaml": "*",
"@opam/ocamlfind": "*"
}
}
--- ./Makefile
+++ ./Makefile
@@ -213,7 +213,7 @@
rm -f man/ocamlbuild.1
man/options_man.byte: src/ocamlbuild_pack.cmo
- $(OCAMLC) $^ -I src man/options_man.ml -o man/options_man.byte
+ $(OCAMLC) -I +unix unix.cma $^ -I src man/options_man.ml -o man/options_man.byte
clean::
rm -f man/options_man.cm*
--- ./src/command.ml
+++ ./src/command.ml
@@ -148,9 +148,10 @@
let self = string_of_command_spec_with_calls call_with_tags call_with_target resolve_virtuals in
let b = Buffer.create 256 in
(* The best way to prevent bash from switching to its windows-style
- * quote-handling is to prepend an empty string before the command name. *)
+ * quote-handling is to prepend an empty string before the command name.
+ * space seems to work, too - and the ouput is nicer *)
if Sys.os_type = "Win32" then
- Buffer.add_string b "''";
+ Buffer.add_char b ' ';
let first = ref true in
let put_space () =
if !first then
@@ -260,7 +261,7 @@
let execute_many ?(quiet=false) ?(pretend=false) cmds =
add_parallel_stat (List.length cmds);
- let degraded = !*My_unix.is_degraded || Sys.os_type = "Win32" in
+ let degraded = !*My_unix.is_degraded in
let jobs = !jobs in
if jobs < 0 then invalid_arg "jobs < 0";
let max_jobs = if jobs = 0 then None else Some jobs in
--- ./src/findlib.ml
+++ ./src/findlib.ml
@@ -66,9 +66,6 @@
(fun command -> lexer & Lexing.from_string & run_and_read command)
command
-let run_and_read command =
- Printf.ksprintf run_and_read command
-
let rec query name =
try
Hashtbl.find packages name
@@ -135,7 +132,8 @@
with Not_found -> s
let list () =
- List.map before_space (split_nl & run_and_read "%s list" ocamlfind)
+ let cmd = Shell.quote_filename_if_needed ocamlfind ^ " list" in
+ List.map before_space (split_nl & run_and_read cmd)
(* The closure algorithm is easy because the dependencies are already closed
and sorted for each package. We only have to make the union. We could also
--- ./src/main.ml
+++ ./src/main.ml
@@ -162,6 +162,9 @@
Tags.mem "traverse" tags
|| List.exists (Pathname.is_prefix path_name) !Options.include_dirs
|| List.exists (Pathname.is_prefix path_name) target_dirs)
+ && ((* beware: !Options.build_dir is an absolute directory *)
+ Pathname.normalize !Options.build_dir
+ <> Pathname.normalize (Pathname.pwd/path_name))
end
end
end
--- ./src/my_std.ml
+++ ./src/my_std.ml
@@ -271,13 +271,107 @@
try Array.iter (fun x -> if x = basename then raise Exit) a; false
with Exit -> true
+let command_plain = function
+| [| |] -> 0
+| margv ->
+ let rec waitpid a b =
+ match Unix.waitpid a b with
+ | exception (Unix.Unix_error(Unix.EINTR,_,_)) -> waitpid a b
+ | x -> x
+ in
+ let pid = Unix.(create_process margv.(0) margv stdin stdout stderr) in
+ let pid', process_status = waitpid [] pid in
+ assert (pid = pid');
+ match process_status with
+ | Unix.WEXITED n -> n
+ | Unix.WSIGNALED _ -> 2 (* like OCaml's uncaught exceptions *)
+ | Unix.WSTOPPED _ -> 127
+
+(* can't use Lexers because of circular dependency *)
+let split_path_win str =
+ let rec aux pos =
+ try
+ let i = String.index_from str pos ';' in
+ let len = i - pos in
+ if len = 0 then
+ aux (succ i)
+ else
+ String.sub str pos (i - pos) :: aux (succ i)
+ with Not_found | Invalid_argument _ ->
+ let len = String.length str - pos in
+ if len = 0 then [] else [String.sub str pos len]
+ in
+ aux 0
+
+let windows_shell = lazy begin
+ let rec iter = function
+ | [] -> [| "bash.exe" ; "--norc" ; "--noprofile" |]
+ | hd::tl ->
+ let dash = Filename.concat hd "dash.exe" in
+ if Sys.file_exists dash then [|dash|] else
+ let bash = Filename.concat hd "bash.exe" in
+ if Sys.file_exists bash = false then iter tl else
+ (* if sh.exe and bash.exe exist in the same dir, choose sh.exe *)
+ let sh = Filename.concat hd "sh.exe" in
+ if Sys.file_exists sh then [|sh|] else [|bash ; "--norc" ; "--noprofile"|]
+ in
+ split_path_win (try Sys.getenv "PATH" with Not_found -> "") |> iter
+end
+
+let prep_windows_cmd cmd =
+ (* workaround known ocaml bug, remove later *)
+ if String.contains cmd '\t' && String.contains cmd ' ' = false then
+ " " ^ cmd
+ else
+ cmd
+
+let run_with_shell = function
+| "" -> 0
+| cmd ->
+ let cmd = prep_windows_cmd cmd in
+ let shell = Lazy.force windows_shell in
+ let qlen = Filename.quote cmd |> String.length in
+ (* old versions of dash had problems with bs *)
+ try
+ if qlen < 7_900 then
+ command_plain (Array.append shell [| "-ec" ; cmd |])
+ else begin
+ (* it can still work, if the called command is a cygwin tool *)
+ let ch_closed = ref false in
+ let file_deleted = ref false in
+ let fln,ch =
+ Filename.open_temp_file
+ ~mode:[Open_binary]
+ "ocamlbuildtmp"
+ ".sh"
+ in
+ try
+ let f_slash = String.map ( fun x -> if x = '\\' then '/' else x ) fln in
+ output_string ch cmd;
+ ch_closed:= true;
+ close_out ch;
+ let ret = command_plain (Array.append shell [| "-e" ; f_slash |]) in
+ file_deleted:= true;
+ Sys.remove fln;
+ ret
+ with
+ | x ->
+ if !ch_closed = false then
+ close_out_noerr ch;
+ if !file_deleted = false then
+ (try Sys.remove fln with _ -> ());
+ raise x
+ end
+ with
+ | (Unix.Unix_error _) as x ->
+ (* Sys.command doesn't raise an exception, so run_with_shell also won't
+ raise *)
+ Printexc.to_string x ^ ":" ^ cmd |> prerr_endline;
+ 1
+
let sys_command =
- match Sys.os_type with
- | "Win32" -> fun cmd ->
- if cmd = "" then 0 else
- let cmd = "bash --norc -c " ^ Filename.quote cmd in
- Sys.command cmd
- | _ -> fun cmd -> if cmd = "" then 0 else Sys.command cmd
+ if Sys.win32 then run_with_shell
+ else fun cmd -> if cmd = "" then 0 else Sys.command cmd
(* FIXME warning fix and use Filename.concat *)
let filename_concat x y =
--- ./src/my_std.mli
+++ ./src/my_std.mli
@@ -69,3 +69,6 @@
val split_ocaml_version : (int * int * int * string) option
(** (major, minor, patchlevel, rest) *)
+
+val windows_shell : string array Lazy.t
+val prep_windows_cmd : string -> string
--- ./src/ocamlbuild_executor.ml
+++ ./src/ocamlbuild_executor.ml
@@ -34,6 +34,8 @@
job_stdin : out_channel;
job_stderr : in_channel;
job_buffer : Buffer.t;
+ job_pid : int;
+ job_tmp_file: string option;
mutable job_dying : bool;
};;
@@ -76,6 +78,61 @@
in
loop 0
;;
+
+let open_process_full_win cmd env =
+ let (in_read, in_write) = Unix.pipe () in
+ let (out_read, out_write) = Unix.pipe () in
+ let (err_read, err_write) = Unix.pipe () in
+ Unix.set_close_on_exec in_read;
+ Unix.set_close_on_exec out_write;
+ Unix.set_close_on_exec err_read;
+ let inchan = Unix.in_channel_of_descr in_read in
+ let outchan = Unix.out_channel_of_descr out_write in
+ let errchan = Unix.in_channel_of_descr err_read in
+ let shell = Lazy.force Ocamlbuild_pack.My_std.windows_shell in
+ let test_cmd =
+ String.concat " " (List.map Filename.quote (Array.to_list shell)) ^
+ "-ec " ^
+ Filename.quote (Ocamlbuild_pack.My_std.prep_windows_cmd cmd) in
+ let argv,tmp_file =
+ if String.length test_cmd < 7_900 then
+ Array.append
+ shell
+ [| "-ec" ; Ocamlbuild_pack.My_std.prep_windows_cmd cmd |],None
+ else
+ let fln,ch = Filename.open_temp_file ~mode:[Open_binary] "ocamlbuild" ".sh" in
+ output_string ch (Ocamlbuild_pack.My_std.prep_windows_cmd cmd);
+ close_out ch;
+ let fln' = String.map (function '\\' -> '/' | c -> c) fln in
+ Array.append
+ shell
+ [| "-c" ; fln' |], Some fln in
+ let pid =
+ Unix.create_process_env argv.(0) argv env out_read in_write err_write in
+ Unix.close out_read;
+ Unix.close in_write;
+ Unix.close err_write;
+ (pid, inchan, outchan, errchan,tmp_file)
+
+let close_process_full_win (pid,inchan, outchan, errchan, tmp_file) =
+ let delete tmp_file =
+ match tmp_file with
+ | None -> ()
+ | Some x -> try Sys.remove x with Sys_error _ -> () in
+ let tmp_file_deleted = ref false in
+ try
+ close_in inchan;
+ close_out outchan;
+ close_in errchan;
+ let res = snd(Unix.waitpid [] pid) in
+ tmp_file_deleted := true;
+ delete tmp_file;
+ res
+ with
+ | x when tmp_file <> None && !tmp_file_deleted = false ->
+ delete tmp_file;
+ raise x
+
(* ***)
(*** execute *)
(* XXX: Add test for non reentrancy *)
@@ -130,10 +187,16 @@
(*** add_job *)
let add_job cmd rest result id =
(*display begin fun oc -> fp oc "Job %a is %s\n%!" print_job_id id cmd; end;*)
- let (stdout', stdin', stderr') = open_process_full cmd env in
+ let (pid,stdout', stdin', stderr', tmp_file) =
+ if Sys.win32 then open_process_full_win cmd env else
+ let a,b,c = open_process_full cmd env in
+ -1,a,b,c,None
+ in
incr jobs_active;
- set_nonblock (doi stdout');
- set_nonblock (doi stderr');
+ if not Sys.win32 then (
+ set_nonblock (doi stdout');
+ set_nonblock (doi stderr');
+ );
let job =
{ job_id = id;
job_command = cmd;
@@ -143,7 +206,9 @@
job_stdin = stdin';
job_stderr = stderr';
job_buffer = Buffer.create 1024;
- job_dying = false }
+ job_dying = false;
+ job_tmp_file = tmp_file;
+ job_pid = pid }
in
outputs := FDM.add (doi stdout') job (FDM.add (doi stderr') job !outputs);
jobs := JS.add job !jobs;
@@ -199,6 +264,7 @@
try
read fd u 0 (Bytes.length u)
with
+ | Unix.Unix_error(Unix.EPIPE,_,_) when Sys.win32 -> 0
| Unix.Unix_error(e,_,_) ->
let msg = error_message e in
display (fun oc -> fp oc
@@ -241,14 +307,19 @@
decr jobs_active;
(* PR#5371: we would get EAGAIN below otherwise *)
- clear_nonblock (doi job.job_stdout);
- clear_nonblock (doi job.job_stderr);
-
+ if not Sys.win32 then (
+ clear_nonblock (doi job.job_stdout);
+ clear_nonblock (doi job.job_stderr);
+ );
do_read ~loop:true (doi job.job_stdout) job;
do_read ~loop:true (doi job.job_stderr) job;
outputs := FDM.remove (doi job.job_stdout) (FDM.remove (doi job.job_stderr) !outputs);
jobs := JS.remove job !jobs;
- let status = close_process_full (job.job_stdout, job.job_stdin, job.job_stderr) in
+ let status =
+ if Sys.win32 then
+ close_process_full_win (job.job_pid, job.job_stdout, job.job_stdin, job.job_stderr, job.job_tmp_file)
+ else
+ close_process_full (job.job_stdout, job.job_stdin, job.job_stderr) in
let shown = ref false in
--- ./src/ocamlbuild_unix_plugin.ml
+++ ./src/ocamlbuild_unix_plugin.ml
@@ -48,12 +48,22 @@
end
let run_and_open s kont =
+ let s_orig = s in
+ let s =
+ (* Be consistent! My_unix.run_and_open uses My_std.sys_command and
+ sys_command uses bash. *)
+ if Sys.win32 = false then s else
+ let l = match Lazy.force My_std.windows_shell |> Array.to_list with
+ | hd::tl -> (Filename.quote hd)::tl
+ | _ -> assert false in
+ "\"" ^ (String.concat " " l) ^ " -ec " ^ Filename.quote (" " ^ s) ^ "\""
+ in
let ic = Unix.open_process_in s in
let close () =
match Unix.close_process_in ic with
| Unix.WEXITED 0 -> ()
| Unix.WEXITED _ | Unix.WSIGNALED _ | Unix.WSTOPPED _ ->
- failwith (Printf.sprintf "Error while running: %s" s) in
+ failwith (Printf.sprintf "Error while running: %s" s_orig) in
let res = try
kont ic
with e -> (close (); raise e)
--- ./src/options.ml
+++ ./src/options.ml
@@ -174,11 +174,24 @@
build_dir := Filename.concat (Sys.getcwd ()) s
else
build_dir := s
+
+let slashify =
+ if Sys.win32 then fun p -> String.map (function '\\' -> '/' | x -> x) p
+ else fun p ->p
+
+let sb () =
+ match Sys.os_type with
+ | "Win32" ->
+ (try set_binary_mode_out stdout true with _ -> ());
+ | _ -> ()
+
+
let spec = ref (
let print_version () =
+ sb ();
Printf.printf "ocamlbuild %s\n%!" Ocamlbuild_config.version; raise Exit_OK
in
- let print_vnum () = print_endline Ocamlbuild_config.version; raise Exit_OK in
+ let print_vnum () = sb (); print_endline Ocamlbuild_config.version; raise Exit_OK in
Arg.align
[
"-version", Unit print_version , " Display the version";
@@ -257,8 +270,8 @@
"-build-dir", String set_build_dir, "<path> Set build directory (implies no-links)";
"-install-lib-dir", Set_string Ocamlbuild_where.libdir, "<path> Set the install library directory";
"-install-bin-dir", Set_string Ocamlbuild_where.bindir, "<path> Set the install binary directory";
- "-where", Unit (fun () -> print_endline !Ocamlbuild_where.libdir; raise Exit_OK), " Display the install library directory";
- "-which", String (fun cmd -> print_endline (find_tool cmd); raise Exit_OK), "<command> Display path to the tool command";
+ "-where", Unit (fun () -> sb (); print_endline (slashify !Ocamlbuild_where.libdir); raise Exit_OK), " Display the install library directory";
+ "-which", String (fun cmd -> sb (); print_endline (slashify (find_tool cmd)); raise Exit_OK), "<command> Display path to the tool command";
"-ocamlc", set_cmd ocamlc, "<command> Set the OCaml bytecode compiler";
"-plugin-ocamlc", set_cmd plugin_ocamlc, "<command> Set the OCaml bytecode compiler \
used when building myocamlbuild.ml (only)";
--- ./src/pathname.ml
+++ ./src/pathname.ml
@@ -84,6 +84,26 @@
| x :: xs -> x :: normalize_list xs
let normalize x =
+ let x =
+ if Sys.win32 = false then
+ x
+ else
+ let len = String.length x in
+ let b = Bytes.create len in
+ for i = 0 to pred len do
+ match x.[i] with
+ | '\\' -> Bytes.set b i '/'
+ | c -> Bytes.set b i c
+ done;
+ if len > 1 then (
+ let c1 = Bytes.get b 0 in
+ let c2 = Bytes.get b 1 in
+ if c2 = ':' && c1 >= 'a' && c1 <= 'z' &&
+ ( len = 2 || Bytes.get b 2 = '/') then
+ Bytes.set b 0 (Char.uppercase_ascii c1)
+ );
+ Bytes.unsafe_to_string b
+ in
if Glob.eval not_normal_form_re x then
let root, paths = split x in
join root (normalize_list paths)
--- ./src/shell.ml
+++ ./src/shell.ml
@@ -24,12 +24,26 @@
| 'a'..'z' | 'A'..'Z' | '0'..'9' | '.' | '-' | '/' | '_' | ':' | '@' | '+' | ',' -> loop (pos + 1)
| _ -> false in
loop 0
+
+let generic_quote quotequote s =
+ let l = String.length s in
+ let b = Buffer.create (l + 20) in
+ Buffer.add_char b '\'';
+ for i = 0 to l - 1 do
+ if s.[i] = '\''
+ then Buffer.add_string b quotequote
+ else Buffer.add_char b s.[i]
+ done;
+ Buffer.add_char b '\'';
+ Buffer.contents b
+let unix_quote = generic_quote "'\\''"
+
let quote_filename_if_needed s =
if is_simple_filename s then s
(* We should probably be using [Filename.unix_quote] except that function
* isn't exported. Users on Windows will have to live with not being able to
* install OCaml into c:\o'caml. Too bad. *)
- else if Sys.os_type = "Win32" then Printf.sprintf "'%s'" s
+ else if Sys.os_type = "Win32" then unix_quote s
else Filename.quote s
let chdir dir =
reset_filesys_cache ();
@@ -37,7 +51,7 @@
let run args target =
reset_readdir_cache ();
let cmd = String.concat " " (List.map quote_filename_if_needed args) in
- if !*My_unix.is_degraded || Sys.os_type = "Win32" then
+ if !*My_unix.is_degraded then
begin
Log.event cmd target Tags.empty;
let st = sys_command cmd in
{
"build": [
[
"bash",
"-c",
"#{os == 'windows' ? 'patch -p1 < ocamlbuild-0.14.0.patch' : 'true'}"
],
[
"make",
"-f",
"configure.make",
"all",
"OCAMLBUILD_PREFIX=#{self.install}",
"OCAMLBUILD_BINDIR=#{self.bin}",
"OCAMLBUILD_LIBDIR=#{self.lib}",
"OCAMLBUILD_MANDIR=#{self.man}",
"OCAMLBUILD_NATIVE=true",
"OCAMLBUILD_NATIVE_TOOLS=true"
],
[
"make",
"check-if-preinstalled",
"all",
"#{os == 'windows' ? 'install' : 'opam-install'}"
]
]
}
--- ./Makefile
+++ ./Makefile
@@ -57,16 +57,16 @@
cat findlib.conf.in | \
$(SH) tools/patch '@SITELIB@' '$(OCAML_SITELIB)' >findlib.conf
if ./tools/cmd_from_same_dir ocamlc; then \
- echo 'ocamlc="ocamlc.opt"' >>findlib.conf; \
+ echo 'ocamlc="ocamlc.opt$(EXEC_SUFFIX)"' >>findlib.conf; \
fi
if ./tools/cmd_from_same_dir ocamlopt; then \
- echo 'ocamlopt="ocamlopt.opt"' >>findlib.conf; \
+ echo 'ocamlopt="ocamlopt.opt$(EXEC_SUFFIX)"' >>findlib.conf; \
fi
if ./tools/cmd_from_same_dir ocamldep; then \
- echo 'ocamldep="ocamldep.opt"' >>findlib.conf; \
+ echo 'ocamldep="ocamldep.opt$(EXEC_SUFFIX)"' >>findlib.conf; \
fi
if ./tools/cmd_from_same_dir ocamldoc; then \
- echo 'ocamldoc="ocamldoc.opt"' >>findlib.conf; \
+ echo 'ocamldoc="ocamldoc.opt$(EXEC_SUFFIX)"' >>findlib.conf; \
fi
.PHONY: install-doc
--- ./src/findlib/findlib_config.mlp
+++ ./src/findlib/findlib_config.mlp
@@ -24,3 +24,5 @@
| "MacOS" -> "" (* don't know *)
| _ -> failwith "Unknown Sys.os_type"
;;
+
+let exec_suffix = "@EXEC_SUFFIX@";;
--- ./src/findlib/findlib.ml
+++ ./src/findlib/findlib.ml
@@ -28,15 +28,20 @@
let conf_ldconf = ref "";;
let conf_ignore_dups_in = ref ([] : string list);;
-let ocamlc_default = "ocamlc";;
-let ocamlopt_default = "ocamlopt";;
-let ocamlcp_default = "ocamlcp";;
-let ocamloptp_default = "ocamloptp";;
-let ocamlmklib_default = "ocamlmklib";;
-let ocamlmktop_default = "ocamlmktop";;
-let ocamldep_default = "ocamldep";;
-let ocamlbrowser_default = "ocamlbrowser";;
-let ocamldoc_default = "ocamldoc";;
+let add_exec str =
+ match Findlib_config.exec_suffix with
+ | "" -> str
+ | a -> str ^ a ;;
+let ocamlc_default = add_exec "ocamlc";;
+let ocamlopt_default = add_exec "ocamlopt";;
+let ocamlcp_default = add_exec "ocamlcp";;
+let ocamloptp_default = add_exec "ocamloptp";;
+let ocamlmklib_default = add_exec "ocamlmklib";;
+let ocamlmktop_default = add_exec "ocamlmktop";;
+let ocamldep_default = add_exec "ocamldep";;
+let ocamlbrowser_default = add_exec "ocamlbrowser";;
+let ocamldoc_default = add_exec "ocamldoc";;
+
let init_manually
--- ./src/findlib/fl_package_base.ml
+++ ./src/findlib/fl_package_base.ml
@@ -133,7 +133,15 @@
List.find (fun def -> def.def_var = "exists_if") p.package_defs in
let files = Fl_split.in_words def.def_value in
List.exists
- (fun file -> Sys.file_exists (Filename.concat d' file))
+ (fun file ->
+ let fln = Filename.concat d' file in
+ let e = Sys.file_exists fln in
+ (* necessary for ppx executables *)
+ if e || Sys.os_type <> "Win32" || Filename.check_suffix fln ".exe" then
+ e
+ else
+ Sys.file_exists (fln ^ ".exe")
+ )
files
with Not_found -> true in
--- ./src/findlib/fl_split.ml
+++ ./src/findlib/fl_split.ml
@@ -126,10 +126,17 @@
| '/' | '\\' -> true
| _ -> false in
let norm_dir_win() =
- if l >= 1 && s.[0] = '/' then
- Buffer.add_char b '\\' else Buffer.add_char b s.[0];
- if l >= 2 && s.[1] = '/' then
- Buffer.add_char b '\\' else Buffer.add_char b s.[1];
+ if l >= 1 then (
+ if s.[0] = '/' then
+ Buffer.add_char b '\\'
+ else
+ Buffer.add_char b s.[0] ;
+ if l >= 2 then
+ if s.[1] = '/' then
+ Buffer.add_char b '\\'
+ else
+ Buffer.add_char b s.[1];
+ );
for k = 2 to l - 1 do
let c = s.[k] in
if is_slash c then (
--- ./src/findlib/frontend.ml
+++ ./src/findlib/frontend.ml
@@ -31,10 +31,18 @@
else
Sys_error (arg ^ ": " ^ Unix.error_message code)
+let is_win = Sys.os_type = "Win32"
+
+let () =
+ match Findlib_config.system with
+ | "win32" | "win64" | "mingw" | "cygwin" | "mingw64" | "cygwin64" ->
+ (try set_binary_mode_out stdout true with _ -> ());
+ (try set_binary_mode_out stderr true with _ -> ());
+ | _ -> ()
let slashify s =
match Findlib_config.system with
- | "mingw" | "mingw64" | "cygwin" ->
+ | "win32" | "win64" | "mingw" | "cygwin" | "mingw64" | "cygwin64" ->
let b = Buffer.create 80 in
String.iter
(function
@@ -49,7 +57,7 @@
let out_path ?(prefix="") s =
match Findlib_config.system with
- | "mingw" | "mingw64" | "cygwin" ->
+ | "win32" | "win64" | "mingw" | "mingw64" | "cygwin" ->
let u = slashify s in
prefix ^
(if String.contains u ' ' then
@@ -273,11 +281,9 @@
let identify_dir d =
- match Sys.os_type with
- | "Win32" ->
- failwith "identify_dir" (* not available *)
- | _ ->
- let s = Unix.stat d in
+ if is_win then
+ failwith "identify_dir"; (* not available *)
+ let s = Unix.stat d in
(s.Unix.st_dev, s.Unix.st_ino)
;;
@@ -459,6 +465,96 @@
)
packages
+let rewrite_cmd s =
+ if s = "" || not is_win then
+ s
+ else
+ let s =
+ let l = String.length s in
+ let b = Buffer.create l in
+ for i = 0 to pred l do
+ match s.[i] with
+ | '/' -> Buffer.add_char b '\\'
+ | x -> Buffer.add_char b x
+ done;
+ Buffer.contents b
+ in
+ if (Filename.is_implicit s && String.contains s '\\' = false) ||
+ Filename.check_suffix (String.lowercase s) ".exe" then
+ s
+ else
+ let s' = s ^ ".exe" in
+ if Sys.file_exists s' then
+ s'
+ else
+ s
+
+let rewrite_cmd s =
+ if s = "" || not is_win then s else
+ let s =
+ let l = String.length s in
+ let b = Buffer.create l in
+ for i = 0 to pred l do
+ match s.[i] with
+ | '/' -> Buffer.add_char b '\\'
+ | x -> Buffer.add_char b x
+ done;
+ Buffer.contents b
+ in
+ if (Filename.is_implicit s && String.contains s '\\' = false) ||
+ Filename.check_suffix (String.lowercase s) ".exe" then
+ s
+ else
+ let s' = s ^ ".exe" in
+ if Sys.file_exists s' then
+ s'
+ else
+ s
+
+let rewrite_pp cmd =
+ if not is_win then cmd else
+ let module T = struct exception Keep end in
+ let is_whitespace = function
+ | ' ' | '\011' | '\012' | '\n' | '\r' | '\t' -> true
+ | _ -> false in
+ (* characters that triggers special behaviour (cmd.exe, not unix shell) *)
+ let is_unsafe_char = function
+ | '(' | ')' | '%' | '!' | '^' | '<' | '>' | '&' -> true
+ | _ -> false in
+ let len = String.length cmd in
+ let buf = Buffer.create (len + 4) in
+ let buf_cmd = Buffer.create len in
+ let rec iter_ws i =
+ if i >= len then () else
+ let cur = cmd.[i] in
+ if is_whitespace cur then (
+ Buffer.add_char buf cur;
+ iter_ws (succ i)
+ )
+ else
+ iter_cmd i
+ and iter_cmd i =
+ if i >= len then add_buf_cmd () else
+ let cur = cmd.[i] in
+ if is_unsafe_char cur || cur = '"' || cur = '\'' then
+ raise T.Keep;
+ if is_whitespace cur then (
+ add_buf_cmd ();
+ Buffer.add_substring buf cmd i (len - i)
+ )
+ else (
+ Buffer.add_char buf_cmd cur;
+ iter_cmd (succ i)
+ )
+ and add_buf_cmd () =
+ if Buffer.length buf_cmd > 0 then
+ Buffer.add_string buf (rewrite_cmd (Buffer.contents buf_cmd))
+ in
+ try
+ iter_ws 0;
+ Buffer.contents buf
+ with
+ | T.Keep -> cmd
let process_pp_spec syntax_preds packages pp_opts =
(* Returns: pp_command *)
@@ -549,7 +645,7 @@
None -> []
| Some cmd ->
["-pp";
- cmd ^ " " ^
+ (rewrite_cmd cmd) ^ " " ^
String.concat " " (List.map Filename.quote pp_i_options) ^ " " ^
String.concat " " (List.map Filename.quote pp_archives) ^ " " ^
String.concat " " (List.map Filename.quote pp_opts)]
@@ -625,9 +721,11 @@
in
try
let preprocessor =
+ rewrite_cmd (
resolve_path
~base ~explicit:true
- (package_property predicates pname "ppx") in
+ (package_property predicates pname "ppx") )
+ in
["-ppx"; String.concat " " (preprocessor :: options)]
with Not_found -> []
)
@@ -895,6 +993,14 @@
switch (e.g. -L<path> instead of -L <path>)
*)
+(* We may need to remove files on which we do not have complete control.
+ On Windows, removing a read-only file fails so try to change the
+ mode of the file first. *)
+let remove_file fname =
+ try Sys.remove fname
+ with Sys_error _ when is_win ->
+ (try Unix.chmod fname 0o666 with Unix.Unix_error _ -> ());
+ Sys.remove fname
let ocamlc which () =
@@ -1022,9 +1128,12 @@
"-intf",
Arg.String (fun s -> pass_files := !pass_files @ [ Intf(slashify s) ]);
-
+
"-pp",
- Arg.String (fun s -> pp_specified := true; add_spec_fn "-pp" s);
+ Arg.String (fun s -> pp_specified := true; add_spec_fn "-pp" (rewrite_pp s));
+
+ "-ppx",
+ Arg.String (fun s -> add_spec_fn "-ppx" (rewrite_pp s));
"-thread",
Arg.Unit (fun _ -> threads := threads_default);
@@ -1237,7 +1346,7 @@
with
any ->
close_out initl;
- Sys.remove initl_file_name;
+ remove_file initl_file_name;
raise any
end;
@@ -1245,9 +1354,9 @@
at_exit
(fun () ->
let tr f x = try f x with _ -> () in
- tr Sys.remove initl_file_name;
- tr Sys.remove (Filename.chop_extension initl_file_name ^ ".cmi");
- tr Sys.remove (Filename.chop_extension initl_file_name ^ ".cmo");
+ tr remove_file initl_file_name;
+ tr remove_file (Filename.chop_extension initl_file_name ^ ".cmi");
+ tr remove_file (Filename.chop_extension initl_file_name ^ ".cmo");
);
let exclude_list = [ stdlibdir; threads_dir; vmthreads_dir ] in
@@ -1493,7 +1602,9 @@
[ "-v", Arg.Unit (fun () -> verbose := Verbose);
"-pp", Arg.String (fun s ->
pp_specified := true;
- options := !options @ ["-pp"; s]);
+ options := !options @ ["-pp"; rewrite_pp s]);
+ "-ppx", Arg.String (fun s ->
+ options := !options @ ["-ppx"; rewrite_pp s]);
]
)
)
@@ -1672,7 +1783,9 @@
Arg.String (fun s -> add_spec_fn "-I" (slashify (resolve_path s)));
"-pp", Arg.String (fun s -> pp_specified := true;
- add_spec_fn "-pp" s);
+ add_spec_fn "-pp" (rewrite_pp s));
+ "-ppx", Arg.String (fun s -> add_spec_fn "-ppx" (rewrite_pp s));
+
]
)
)
@@ -1830,7 +1943,10 @@
output_string ch_out append;
close_out ch_out;
close_in ch_in;
- Unix.utimes outpath s.Unix.st_mtime s.Unix.st_mtime;
+ (try Unix.utimes outpath s.Unix.st_mtime s.Unix.st_mtime
+ with Unix.Unix_error(e,_,_) ->
+ prerr_endline("Warning: setting utimes for " ^ outpath
+ ^ ": " ^ Unix.error_message e));
prerr_endline("Installed " ^ outpath);
with
@@ -1882,6 +1998,8 @@
Unix.openfile (Filename.concat dir owner_file) [Unix.O_RDONLY] 0 in
let f =
Unix.in_channel_of_descr fd in
+ if is_win then
+ set_binary_mode_in f false;
try
let line = input_line f in
let is_my_file = (line = pkg) in
@@ -2208,7 +2326,7 @@
let lines = read_ldconf !ldconf in
let dlldir_norm = Fl_split.norm_dir dlldir in
let dlldir_norm_lc = string_lowercase_ascii dlldir_norm in
- let ci_filesys = (Sys.os_type = "Win32") in
+ let ci_filesys = is_win in
let check_dir d =
let d' = Fl_split.norm_dir d in
(d' = dlldir_norm) ||
@@ -2356,7 +2474,7 @@
List.iter
(fun file ->
let absfile = Filename.concat dlldir file in
- Sys.remove absfile;
+ remove_file absfile;
prerr_endline ("Removed " ^ absfile)
)
dll_files
@@ -2365,7 +2483,7 @@
(* Remove the files from the package directory: *)
if Sys.file_exists pkgdir then begin
let files = Sys.readdir pkgdir in
- Array.iter (fun f -> Sys.remove (Filename.concat pkgdir f)) files;
+ Array.iter (fun f -> remove_file (Filename.concat pkgdir f)) files;
Unix.rmdir pkgdir;
prerr_endline ("Removed " ^ pkgdir)
end
@@ -2415,7 +2533,9 @@
let print_configuration() =
+ let sl = slashify in
let dir s =
+ let s = sl s in
if Sys.file_exists s then
s
else
@@ -2453,27 +2573,27 @@
if md = "" then "the corresponding package directories" else dir md
);
Printf.printf "The standard library is assumed to reside in:\n %s\n"
- (Findlib.ocaml_stdlib());
+ (sl (Findlib.ocaml_stdlib()));
Printf.printf "The ld.conf file can be found here:\n %s\n"
- (Findlib.ocaml_ldconf());
+ (sl (Findlib.ocaml_ldconf()));
flush stdout
| Some "conf" ->
- print_endline (Findlib.config_file())
+ print_endline (sl (Findlib.config_file()))
| Some "path" ->
- List.iter print_endline (Findlib.search_path())
+ List.iter ( fun x -> print_endline (sl x)) (Findlib.search_path())
| Some "destdir" ->
- print_endline (Findlib.default_location())
+ print_endline ( sl (Findlib.default_location()))
| Some "metadir" ->
- print_endline (Findlib.meta_directory())
+ print_endline ( sl (Findlib.meta_directory()))
| Some "metapath" ->
let mdir = Findlib.meta_directory() in
let ddir = Findlib.default_location() in
- print_endline
- (if mdir <> "" then mdir ^ "/META.%s" else ddir ^ "/%s/META")
+ print_endline ( sl
+ (if mdir <> "" then mdir ^ "/META.%s" else ddir ^ "/%s/META"))
| Some "stdlib" ->
- print_endline (Findlib.ocaml_stdlib())
+ print_endline ( sl (Findlib.ocaml_stdlib()))
| Some "ldconf" ->
- print_endline (Findlib.ocaml_ldconf())
+ print_endline ( sl (Findlib.ocaml_ldconf()))
| _ ->
assert false
;;
@@ -2481,7 +2601,7 @@
let ocamlcall pkg cmd =
let dir = package_directory pkg in
- let path = Filename.concat dir cmd in
+ let path = rewrite_cmd (Filename.concat dir cmd) in
begin
try Unix.access path [ Unix.X_OK ]
with
@@ -2647,6 +2767,10 @@
| Sys_error f ->
prerr_endline ("ocamlfind: " ^ f);
exit 2
+ | Unix.Unix_error (e, fn, f) ->
+ prerr_endline ("ocamlfind: " ^ fn ^ " " ^ f
+ ^ ": " ^ Unix.error_message e);
+ exit 2
| Findlib.No_such_package(pkg,info) ->
prerr_endline ("ocamlfind: Package `" ^ pkg ^ "' not found" ^
(if info <> "" then " - " ^ info else ""));
--- ./src/findlib/Makefile
+++ ./src/findlib/Makefile
@@ -90,6 +90,7 @@
cat findlib_config.mlp | \
$(SH) $(TOP)/tools/patch '@CONFIGFILE@' '$(OCAMLFIND_CONF)' | \
$(SH) $(TOP)/tools/patch '@STDLIB@' '$(OCAML_CORE_STDLIB)' | \
+ $(SH) $(TOP)/tools/patch '@EXEC_SUFFIX@' '$(EXEC_SUFFIX)' | \
sed -e 's;@AUTOLINK@;$(OCAML_AUTOLINK);g' \
-e 's;@SYSTEM@;$(SYSTEM);g' \
>findlib_config.ml
{
"build": [
[
"bash",
"-c",
"#{os == 'windows' ? 'patch -p1 < findlib-1.8.1.patch' : 'true'}"
],
[
"./configure",
"-bindir",
"#{self.bin}",
"-sitelib",
"#{self.lib}",
"-mandir",
"#{self.man}",
"-config",
"#{self.lib}/findlib.conf",
"-no-custom",
"-no-topfind"
],
[
"make",
"all"
],
[
"make",
"opt"
]
],
"install": [
[
"make",
"install"
],
[
"install",
"-m",
"0755",
"ocaml-stub",
"#{self.bin}/ocaml"
],
[
"mkdir",
"-p",
"#{self.toplevel}"
],
[
"install",
"-m",
"0644",
"src/findlib/topfind",
"#{self.toplevel}/topfind"
]
],
"exportedEnv": {
"OCAML_TOPLEVEL_PATH": {
"val": "#{self.toplevel}",
"scope": "global"
}
}
}
module C = Configurator.V1
let () =
C.main ~name:"opus-pkg-config" (fun c ->
let default = { C.Pkg_config.libs = [ "-lopus" ]; cflags = [] } in
let conf =
match C.Pkg_config.get c with
| None -> default
| Some pc -> (
match C.Pkg_config.query pc ~package:"opus" with
| None -> default
| Some deps -> deps)
in
C.Flags.write_sexp "c_flags.sexp" conf.cflags;
C.Flags.write_sexp "c_library_flags.sexp" conf.libs;
C.Flags.write_lines "c_flags.lines" conf.cflags)
(executable
(name discover)
(libraries dune.configurator))
(rule
(targets c_flags.sexp c_library_flags.sexp c_flags.lines)
(deps
(:discover config/discover.exe))
(action
(run %{discover})))
(rule
(targets opus.ml opus_stubs.c)
(deps
(:gen opus.c.ml)
c_flags.lines)
(action
(chdir
%{workspace_root}
(run
%{bin:ppx_cstubs}
%{gen}
-pkg
ctypes
-o
%{targets}
--
%{read-lines:c_flags.lines}))))
(library
(name opus)
(public_name opus)
(wrapped false)
(private_modules
(:standard \ opus))
(libraries unix ctypes ctypes.foreign ppx_cstubs)
(preprocess
(pps ppx_cstubs.merlin))
(foreign_stubs
(language c)
(names opus_stubs)
(flags
(:standard
(:include c_flags.sexp))))
(c_library_flags
(:standard
(:include c_library_flags.sexp))))
let%c () = header {|
#include <opus.h>
#include <opus_multistream.h>
|}
open Ctypes
module C = struct
let app_VOIP = [%c constant "OPUS_APPLICATION_VOIP" camlint]
let app_AUDIO = [%c constant "OPUS_APPLICATION_AUDIO" camlint]
let app_RESTRICTED_LOWEDELAY =
[%c constant "OPUS_APPLICATION_RESTRICTED_LOWDELAY" camlint]
let _AUTO = [%c constant "OPUS_AUTO" camlint]
let signal_VOICE = [%c constant "OPUS_SIGNAL_VOICE" camlint]
let signal_MUSIC = [%c constant "OPUS_SIGNAL_MUSIC" camlint]
let br_MAX = [%c constant "OPUS_BITRATE_MAX" camlint]
let ctl_SET_APPLICATION_REQUEST = [%c constant "OPUS_SET_APPLICATION_REQUEST" camlint]
let ctl_GET_APPLICATION_REQUEST = [%c constant "OPUS_GET_APPLICATION_REQUEST" camlint]
let ctl_SET_BITRATE_REQUEST = [%c constant "OPUS_SET_BITRATE_REQUEST" camlint]
let ctl_GET_BITRATE_REQUEST = [%c constant "OPUS_GET_BITRATE_REQUEST" camlint]
let ctl_SET_MAX_BANDWIDTH_REQUEST = [%c constant "OPUS_SET_MAX_BANDWIDTH_REQUEST" camlint]
let ctl_GET_MAX_BANDWIDTH_REQUEST = [%c constant "OPUS_GET_MAX_BANDWIDTH_REQUEST" camlint]
let ctl_SET_VBR_REQUEST = [%c constant "OPUS_SET_VBR_REQUEST" camlint]
let ctl_GET_VBR_REQUEST = [%c constant "OPUS_GET_VBR_REQUEST" camlint]
let ctl_SET_BANDWIDTH_REQUEST = [%c constant "OPUS_SET_BANDWIDTH_REQUEST" camlint]
let ctl_GET_BANDWIDTH_REQUEST = [%c constant "OPUS_GET_BANDWIDTH_REQUEST" camlint]
let ctl_SET_COMPLEXITY_REQUEST = [%c constant "OPUS_SET_COMPLEXITY_REQUEST" camlint]
let ctl_GET_COMPLEXITY_REQUEST = [%c constant "OPUS_GET_COMPLEXITY_REQUEST" camlint]
let ctl_SET_INBAND_FEC_REQUEST = [%c constant "OPUS_SET_INBAND_FEC_REQUEST" camlint]
let ctl_GET_INBAND_FEC_REQUEST = [%c constant "OPUS_GET_INBAND_FEC_REQUEST" camlint]
let ctl_SET_PACKET_LOSS_PERC_REQUEST = [%c constant "OPUS_SET_PACKET_LOSS_PERC_REQUEST" camlint]
let ctl_GET_PACKET_LOSS_PERC_REQUEST = [%c constant "OPUS_GET_PACKET_LOSS_PERC_REQUEST" camlint]
let ctl_SET_DTX_REQUEST = [%c constant "OPUS_SET_DTX_REQUEST" camlint]
let ctl_GET_DTX_REQUEST = [%c constant "OPUS_GET_DTX_REQUEST" camlint]
let ctl_SET_VBR_CONSTRAINT_REQUEST = [%c constant "OPUS_SET_VBR_CONSTRAINT_REQUEST" camlint]
let ctl_GET_VBR_CONSTRAINT_REQUEST = [%c constant "OPUS_GET_VBR_CONSTRAINT_REQUEST" camlint]
let ctl_SET_FORCE_CHANNELS_REQUEST = [%c constant "OPUS_SET_FORCE_CHANNELS_REQUEST" camlint]
let ctl_GET_FORCE_CHANNELS_REQUEST = [%c constant "OPUS_GET_FORCE_CHANNELS_REQUEST" camlint]
let ctl_SET_SIGNAL_REQUEST = [%c constant "OPUS_SET_SIGNAL_REQUEST" camlint]
let ctl_GET_SIGNAL_REQUEST = [%c constant "OPUS_GET_SIGNAL_REQUEST" camlint]
let ctl_GET_LOOKAHEAD_REQUEST = [%c constant "OPUS_GET_LOOKAHEAD_REQUEST" camlint]
let ctl_RESET_STATE = [%c constant "OPUS_RESET_STATE" camlint]
let ctl_GET_SAMPLE_RATE_REQUEST = [%c constant "OPUS_GET_SAMPLE_RATE_REQUEST" camlint]
let ctl_GET_FINAL_RANGE_REQUEST = [%c constant "OPUS_GET_FINAL_RANGE_REQUEST" camlint]
let ctl_GET_PITCH_REQUEST = [%c constant "OPUS_GET_PITCH_REQUEST" camlint]
let ctl_SET_GAIN_REQUEST = [%c constant "OPUS_SET_GAIN_REQUEST" camlint]
let ctl_GET_GAIN_REQUEST = [%c constant "OPUS_GET_GAIN_REQUEST" camlint]
let ctl_SET_LSB_DEPTH_REQUEST = [%c constant "OPUS_SET_LSB_DEPTH_REQUEST" camlint]
let ctl_GET_LSB_DEPTH_REQUEST = [%c constant "OPUS_GET_LSB_DEPTH_REQUEST" camlint]
let ctl_GET_LAST_PACKET_DURATION_REQUEST = [%c constant "OPUS_GET_LAST_PACKET_DURATION_REQUEST" camlint]
let ctl_SET_EXPERT_FRAME_DURATION_REQUEST = [%c constant "OPUS_SET_EXPERT_FRAME_DURATION_REQUEST" camlint]
let ctl_GET_EXPERT_FRAME_DURATION_REQUEST = [%c constant "OPUS_GET_EXPERT_FRAME_DURATION_REQUEST" camlint]
let ctl_SET_PREDICTION_DISABLED_REQUEST = [%c constant "OPUS_SET_PREDICTION_DISABLED_REQUEST" camlint]
let ctl_GET_PREDICTION_DISABLED_REQUEST = [%c constant "OPUS_GET_PREDICTION_DISABLED_REQUEST" camlint]
let ctl_SET_PHASE_INVERSION_DISABLED_REQUEST = [%c constant "OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST" camlint]
let ctl_GET_PHASE_INVERSION_DISABLED_REQUEST = [%c constant "OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST" camlint]
let ctl_GET_IN_DTX_REQUEST = [%c constant "OPUS_GET_IN_DTX_REQUEST" camlint]
end
module Error = struct
let%c t = int
let _ALLOC_FAIL = [%c constant "OPUS_ALLOC_FAIL" camlint]
let _INVALID_STATE = [%c constant "OPUS_INVALID_STATE" camlint]
let _UNIMPLEMENTED = [%c constant "OPUS_UNIMPLEMENTED" camlint]
let _INVALID_PACKET = [%c constant "OPUS_INVALID_PACKET" camlint]
let _INTERNAL_ERROR = [%c constant "OPUS_INTERNAL_ERROR" camlint]
let _BUFFER_TOO_SMALL = [%c constant "OPUS_BUFFER_TOO_SMALL" camlint]
let _BAD_ARG = [%c constant "OPUS_BAD_ARG" camlint]
let _OK = [%c constant "OPUS_OK" camlint]
external to_string: t -> string = "opus_strerror"
type t = [
`Alloc_fail
| `Invalid_state
| `Unimplemented
| `Invalid_packet
| `Internal_error
| `Buffer_too_small
| `Bad_arg
| `Unknown of int ]
let of_int = function
| e when e = _OK -> raise (Invalid_argument "not an error")
| e when e = _ALLOC_FAIL -> `Alloc_fail
| e when e = _INVALID_STATE -> `Invalid_state
| e when e = _UNIMPLEMENTED -> `Unimplemented
| e when e = _INVALID_PACKET -> `Invalid_packet
| e when e = _INTERNAL_ERROR -> `Internal_error
| e when e = _BUFFER_TOO_SMALL -> `Buffer_too_small
| e when e = _BAD_ARG -> `Bad_arg
| other -> `Unknown other
let wrap_lazy fn = function
| e when e = _OK -> Ok (fn ())
| e when e = _ALLOC_FAIL -> Error `Alloc_fail
| e when e = _INVALID_STATE -> Error `Invalid_state
| e when e = _UNIMPLEMENTED -> Error `Unimplemented
| e when e = _INVALID_PACKET -> Error `Invalid_packet
| e when e = _INTERNAL_ERROR -> Error `Internal_error
| e when e = _BUFFER_TOO_SMALL -> Error `Buffer_too_small
| e when e = _BAD_ARG -> Error `Bad_arg
| other -> Error (`Unknown other)
let wrap a = wrap_lazy (fun () -> a)
let to_string = function
| `Alloc_fail -> to_string _ALLOC_FAIL
| `Invalid_state -> to_string _INVALID_STATE
| `Unimplemented -> to_string _UNIMPLEMENTED
| `Invalid_packet -> to_string _INVALID_PACKET
| `Internal_error -> to_string _INTERNAL_ERROR
| `Buffer_too_small -> to_string _BUFFER_TOO_SMALL
| `Bad_arg -> to_string _BAD_ARG
| `Unknown other -> "unknown error: " ^ (string_of_int other)
let show = to_string
let pp fmt t = Format.fprintf fmt "%s" (show t)
end
type nonrec 'a result = ('a, Error.t) result
type 'a handle = unit ptr
let handle_t: 'a handle typ = ptr void
let%c enc_handle: [`enc] handle typ = ptr void
let%c dec_handle: [`dec] handle typ = ptr void
type bandwidth = [
| `Narrow
| `Medium
| `Wide
| `Superwide
| `Full
]
type framesize = [
| `from_arg
| `fs_2_5ms
| `fs_5ms
| `fs_10ms
| `fs_20ms
| `fs_40ms
| `fs_60ms
| `fs_80ms
| `fs_100ms
| `fs_120ms
]
type application =
| Voip
| Audio
| Restricted_lowdelay
module CTL = struct
external opus_encoder_ctl: enc_handle -> int32_t -> int32_t ptr -> Error.t = "opus_encoder_ctl"
external opus_decoder_ctl: dec_handle -> int32_t -> int32_t ptr -> Error.t = "opus_decoder_ctl"
type enc = [`enc]
type dec = [`dec]
type 'a both = [< `enc | `dec] as 'a
type ('handle, 'res) t =
(* generic *)
| Reset_state: (_ both handle, unit) t
| Get_final_range: (_ both handle, int) t
| Get_bandwidth: (_ both handle, [`auto | bandwidth]) t
| Get_sample_rate: (_ both handle, int) t
| Set_phase_inversion_disabled: bool -> (_ both handle, unit) t
| Get_phase_inversion_disabled: (_ both handle, bool) t
| Get_in_DTX: (_ both handle, bool) t
(* encoder *)
| Set_complexity: int -> (enc handle, unit) t
| Get_complexity: (enc handle, int) t
| Set_bitrate: [`auto | `max | `bps of int] -> (enc handle, unit) t
| Get_bitrate: (enc handle, [`auto | `max | `bps of int]) t
| Set_VBR: bool -> (enc handle, unit) t
| Get_VBR: (enc handle, bool) t
| Set_VBR_constraint: bool -> (enc handle, unit) t
| Get_VBR_constraint: (enc handle, bool) t
| Set_force_channels: [`auto | `mono | `stereo] -> (enc handle, unit) t
| Get_force_channels: (enc handle, [`auto | `mono | `stereo]) t
| Set_max_bandwidth: bandwidth -> (enc handle, unit) t
| Get_max_bandwidth: (enc handle, bandwidth) t
| Set_bandwidth: [`auto | bandwidth] -> (enc handle, unit) t
| Set_signal: [`auto | `voice | `music] -> (enc handle, unit) t
| Get_signal: (enc handle, [`auto | `voice | `music]) t
| Set_application: application -> (enc handle, unit) t
| Get_application: (enc handle, application) t
| Get_lookahead: (enc handle, int) t
| Set_inband_FEC: bool -> (enc handle, unit) t
| Get_inband_FEC: (enc handle, bool) t
| Set_packet_loss_perc: int -> (enc handle, unit) t
| Get_packet_loss_perc: (enc handle, int) t
| Set_DTX: bool -> (enc handle, unit) t
| Get_DTX: (enc handle, bool) t
| Set_LSB_depth: int -> (enc handle, unit) t
| Get_LSB_depth: (enc handle, int) t
| Set_expert_frame_duration: framesize -> (enc handle, unit) t
| Get_expert_frame_duration: (enc handle, framesize) t
| Set_prediction_disabled: bool -> (enc handle, unit) t
| Get_prediction_disabled: (enc handle, bool) t
(* decoder *)
let _code: type a b. (a, b) t -> int32 =
fun t ->
let o = match t with
(* generic *)
| Reset_state -> C.ctl_RESET_STATE
| Get_final_range -> C.ctl_GET_FINAL_RANGE_REQUEST
| Get_bandwidth -> C.ctl_GET_BANDWIDTH_REQUEST
| Get_sample_rate -> C.ctl_GET_SAMPLE_RATE_REQUEST
| Set_phase_inversion_disabled _ -> C.ctl_SET_PHASE_INVERSION_DISABLED_REQUEST
| Get_phase_inversion_disabled -> C.ctl_GET_PHASE_INVERSION_DISABLED_REQUEST
| Get_in_DTX -> C.ctl_GET_IN_DTX_REQUEST
(* encoder *)
| Set_complexity _ -> C.ctl_SET_COMPLEXITY_REQUEST
| Get_complexity -> C.ctl_GET_COMPLEXITY_REQUEST
| Set_bitrate _ -> C.ctl_SET_BITRATE_REQUEST
| Get_bitrate -> C.ctl_GET_BITRATE_REQUEST
| Set_VBR _ -> C.ctl_SET_VBR_REQUEST
| Get_VBR -> C.ctl_GET_VBR_REQUEST
| Set_VBR_constraint _ -> C.ctl_SET_VBR_CONSTRAINT_REQUEST
| Get_VBR_constraint -> C.ctl_GET_VBR_CONSTRAINT_REQUEST
| Set_force_channels _ -> C.ctl_SET_FORCE_CHANNELS_REQUEST
| Get_force_channels -> C.ctl_GET_FORCE_CHANNELS_REQUEST
| Set_max_bandwidth _ -> C.ctl_SET_MAX_BANDWIDTH_REQUEST
| Get_max_bandwidth -> C.ctl_GET_MAX_BANDWIDTH_REQUEST
| Set_bandwidth _ -> C.ctl_SET_BANDWIDTH_REQUEST
| Set_signal _ -> C.ctl_SET_SIGNAL_REQUEST
| Get_signal -> C.ctl_GET_SIGNAL_REQUEST
| Set_application _ -> C.ctl_SET_APPLICATION_REQUEST
| Get_application -> C.ctl_GET_APPLICATION_REQUEST
| Get_lookahead -> C.ctl_GET_LOOKAHEAD_REQUEST
| Set_inband_FEC _ -> C.ctl_SET_INBAND_FEC_REQUEST
| Get_inband_FEC -> C.ctl_GET_INBAND_FEC_REQUEST
| Set_packet_loss_perc _ -> C.ctl_SET_PACKET_LOSS_PERC_REQUEST
| Get_packet_loss_perc -> C.ctl_GET_PACKET_LOSS_PERC_REQUEST
| Set_DTX _ -> C.ctl_SET_DTX_REQUEST
| Get_DTX -> C.ctl_GET_DTX_REQUEST
| Set_LSB_depth _ -> C.ctl_SET_LSB_DEPTH_REQUEST
| Get_LSB_depth -> C.ctl_GET_LSB_DEPTH_REQUEST
| Set_expert_frame_duration _ -> C.ctl_SET_EXPERT_FRAME_DURATION_REQUEST
| Get_expert_frame_duration -> C.ctl_GET_EXPERT_FRAME_DURATION_REQUEST
| Set_prediction_disabled _ -> C.ctl_SET_PREDICTION_DISABLED_REQUEST
| Get_prediction_disabled -> C.ctl_GET_PREDICTION_DISABLED_REQUEST
in
Int32.of_int o
let request: type a b. ctl_fn:string -> a handle -> (a, b) t -> b result
= fun ~ctl_fn handle req ->
let code = _code req in
match req with
(* generic *)
| Reset_state ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> returning int) in
fn handle code |> Error.wrap ()
| Get_phase_inversion_disabled ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> ptr int32_t @-> returning int) in
let b = allocate int32_t 0l in
fn handle code b |> Error.wrap (match !@b with | 0l -> false | 1l -> true | _ -> assert false)
(* encoder *)
| Set_complexity c ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> int32_t @-> returning int) in
fn handle code (Int32.of_int c) |> Error.wrap ()
| Get_complexity ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> ptr int32_t @-> returning int) in
let c = allocate int32_t 0l in
fn handle code c |> Error.wrap (Int32.to_int !@c)
| Set_bitrate br ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> int32_t @-> returning int) in
let br = match br with
| `auto -> C._AUTO
| `max -> C.br_MAX
| `bps br -> br
in
fn handle code (Int32.of_int br) |> Error.wrap ()
| Get_bitrate ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> ptr int32_t @-> returning int) in
let br = allocate int32_t 0l in
fn handle code br |> Error.wrap_lazy (fun () ->
match Int32.to_int !@br with
| n when n = C._AUTO -> `auto
| n when n = C.br_MAX -> `max
| o -> `bps o)
| Set_packet_loss_perc plp ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> int32_t @-> returning int) in
fn handle code (Int32.of_int plp) |> Error.wrap ()
| Get_packet_loss_perc ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> ptr int32_t @-> returning int) in
let plp = allocate int32_t 0l in
fn handle code plp |> Error.wrap (Int32.to_int !@plp)
| Set_signal s ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> int32_t @-> returning int) in
let s = match s with
| `auto -> C._AUTO
| `voice -> C.signal_VOICE
| `music -> C.signal_MUSIC
in
fn handle code (Int32.of_int s) |> Error.wrap ()
| Get_signal ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> ptr int32_t @-> returning int) in
let s = allocate int32_t 0l in
fn handle code s
|> Error.wrap_lazy (fun () ->
match Int32.to_int !@s with
| s when s = C._AUTO -> `auto
| s when s = C.signal_VOICE -> `voice
| s when s = C.signal_MUSIC -> `music
| _ -> assert false)
| Set_inband_FEC b ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> int32_t @-> returning int) in
fn handle code (Int32.of_int @@ Bool.to_int b) |> Error.wrap ()
| Get_inband_FEC ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> ptr int32_t @-> returning int) in
let b = allocate int32_t 0l in
fn handle code b |> Error.wrap (match !@b with | 0l -> false | 1l -> true | _ -> assert false)
| Set_LSB_depth d ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> int32_t @-> returning int) in
fn handle code (Int32.of_int d) |> Error.wrap ()
| Get_LSB_depth ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> ptr int32_t @-> returning int) in
let d = allocate int32_t 0l in
fn handle code d |> Error.wrap (Int32.to_int !@d)
| Set_DTX b ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> int32_t @-> returning int) in
fn handle code (Int32.of_int @@ Bool.to_int b) |> Error.wrap ()
| Get_DTX ->
let fn = Foreign.foreign ctl_fn (handle_t @-> int32_t @-> ptr int32_t @-> returning int) in
let b = allocate int32_t 0l in
fn handle code b |> Error.wrap (match !@b with | 0l -> false | 1l -> true | _ -> assert false)
| _ -> assert false
end
module BA = Bigarray
module BA1 = Bigarray.Array1
type bigstring = (char, BA.int8_unsigned_elt, BA.c_layout) BA1.t
type s16frame = (int, BA.int16_signed_elt, BA.c_layout) BA1.t
type f32frame = (int, BA.float32_elt, BA.c_layout) BA1.t
module Encoder = struct
type encoder = [`enc] handle
let%c t = ptr void
external opus_encoder_size: int -> int = "opus_encoder_get_size"
external opus_encoder_init: t -> int32_t -> int -> int -> Error.t = "opus_encoder_init"
external opus_encoder_create: int32_t -> int -> int -> Error.t ptr -> t = "opus_encoder_create"
external opus_encoder_destroy: t -> void = "opus_encoder_destroy"
external opus_encode: t -> pcm:int16_t ptr -> fs:int -> buf:uchar ptr -> max:int -> int = "opus_encode"
external opus_encode_float: t -> pcm:float ptr -> fs:int -> buf:uchar ptr -> max:int -> int = "opus_encode_float"
type t = {
enc: enc;
samplerate: int;
channels: int;
app: application;
}
and enc = | Own of encoder | C of encoder * gc
and gc = unit ptr
type packet = [ `Packet of bigstring | `DTX ]
let recommended_max_size = 4000
let own = true
let _enc = function | Own e | C (e, _) -> e
let create ?(samplerate=48000) ?(channels=`stereo) ?(application=Audio) () =
let c = match channels with | `stereo -> 2 | `mono -> 1 in
let app = match application with
| Voip -> C.app_VOIP
| Audio -> C.app_AUDIO
| Restricted_lowdelay -> C.app_RESTRICTED_LOWEDELAY
in
let err, enc = match own with
| false ->
let err = allocate int (-1) in
let enc = opus_encoder_create Int32.(of_int samplerate) c app err in
let gc =
allocate_n ~finalise:(fun _ -> opus_encoder_destroy enc)
~count:0 void
in
!@err, C (enc, gc)
| true ->
let enc =
allocate_n ~count:(opus_encoder_size c) uchar
|> coerce (ptr uchar) (ptr void)
in
let err = opus_encoder_init enc Int32.(of_int samplerate) c app in
err, Own enc
in
Error.wrap enc err
|> Result.map (fun enc -> {
enc;
samplerate;
channels=c;
app=application;
})
let size { channels; _ } = opus_encoder_size channels
let _encode_blit:
type a b.
t ->
?pcm_off:int ->
?duration:int ->
(a, b, BA.c_layout) BA1.t ->
?buf_off:int ->
?max_size:int ->
bigstring ->
packet result =
fun t ?(pcm_off=0) ?(duration=20) pcm
?(buf_off=0) ?max_size buf ->
let pcm = BA1.sub pcm pcm_off (BA1.dim pcm - pcm_off) in
let buf = BA1.sub buf buf_off (BA1.dim buf - buf_off) in
let max_size = match max_size with
| Some size when size > (BA1.dim buf) ->
raise (Invalid_argument "max_size is bigger than available buf space")
| Some s -> s
| None -> BA1.dim buf
in
let fs = t.samplerate / 1000 * duration in
if BA1.dim pcm < (fs * t.channels) then
raise (Invalid_argument "given pcm frame does not have enough samples");
let buf_p =
(bigarray_start array1 buf) |>
coerce (ptr char) (ptr uchar)
in
let len = match BA1.kind pcm with
| BA.Int16_signed -> opus_encode (_enc t.enc) ~pcm:(bigarray_start array1 pcm) ~fs ~buf:buf_p ~max:max_size
| BA.Float32 -> opus_encode_float (_enc t.enc) ~pcm:(bigarray_start array1 pcm) ~fs ~buf:buf_p ~max:max_size
| _ ->
print_endline "!!!FATAL!!! invalid opus pcm buffer type (must be s16 or f32)";
exit (-1)
in
match len with
| n when n < 0 -> Error (Error.of_int n)
| n when n <= 2 -> Ok `DTX
| n -> Ok (`Packet (BA1.sub buf 0 n))
let encode_blit t ?pcm_off ?duration pcm ?buf_off ?max_size buf =
_encode_blit t ?pcm_off ?duration pcm ?buf_off ?max_size buf
let encode t ?off ?duration ?(max_size=recommended_max_size) pcm =
let buf = BA1.create BA.char BA.c_layout max_size in
_encode_blit t ?pcm_off:off ?duration pcm buf
let encode_blit_float t ?pcm_off ?duration pcm ?buf_off ?max_size buf =
_encode_blit t ?pcm_off ?duration pcm ?buf_off ?max_size buf
let encode_float t ?off ?duration ?(max_size=recommended_max_size) pcm =
let buf = BA1.create BA.char BA.c_layout max_size in
_encode_blit t ?pcm_off:off ?duration pcm buf
let ctl t req = CTL.request ~ctl_fn:"opus_encoder_ctl" (_enc t.enc) req
end
module Error: sig
type t
val to_string: t -> string
val show: t -> string
val pp: Format.formatter -> t -> unit
end
type nonrec 'a result = ('a, Error.t) result
type 'a handle
type bandwidth = [
| `Narrow
| `Medium
| `Wide
| `Superwide
| `Full
]
type framesize = [
| `from_arg
| `fs_2_5ms
| `fs_5ms
| `fs_10ms
| `fs_20ms
| `fs_40ms
| `fs_60ms
| `fs_80ms
| `fs_100ms
| `fs_120ms
]
type application =
| Voip
| Audio
| Restricted_lowdelay
module CTL: sig
type enc = [`enc]
type dec = [`dec]
type 'a both = [< `enc | `dec] as 'a
type ('handle, 'res) t =
(* generic *)
| Reset_state: (_ both handle, unit) t
| Get_final_range: (_ both handle, int) t
| Get_bandwidth: (_ both handle, [`auto | bandwidth]) t
| Get_sample_rate: (_ both handle, int) t
| Set_phase_inversion_disabled: bool -> (_ both handle, unit) t
| Get_phase_inversion_disabled: (_ both handle, bool) t
| Get_in_DTX: (_ both handle, bool) t
(* encoder *)
| Set_complexity: int -> (enc handle, unit) t
| Get_complexity: (enc handle, int) t
| Set_bitrate: [`auto | `max | `bps of int] -> (enc handle, unit) t
| Get_bitrate: (enc handle, [`auto | `max | `bps of int]) t
| Set_VBR: bool -> (enc handle, unit) t
| Get_VBR: (enc handle, bool) t
| Set_VBR_constraint: bool -> (enc handle, unit) t
| Get_VBR_constraint: (enc handle, bool) t
| Set_force_channels: [`auto | `mono | `stereo] -> (enc handle, unit) t
| Get_force_channels: (enc handle, [`auto | `mono | `stereo]) t
| Set_max_bandwidth: bandwidth -> (enc handle, unit) t
| Get_max_bandwidth: (enc handle, bandwidth) t
| Set_bandwidth: [`auto | bandwidth] -> (enc handle, unit) t
| Set_signal: [`auto | `voice | `music] -> (enc handle, unit) t
| Get_signal: (enc handle, [`auto | `voice | `music]) t
| Set_application: application -> (enc handle, unit) t
| Get_application: (enc handle, application) t
| Get_lookahead: (enc handle, int) t
| Set_inband_FEC: bool -> (enc handle, unit) t
| Get_inband_FEC: (enc handle, bool) t
| Set_packet_loss_perc: int -> (enc handle, unit) t
| Get_packet_loss_perc: (enc handle, int) t
| Set_DTX: bool -> (enc handle, unit) t
| Get_DTX: (enc handle, bool) t
| Set_LSB_depth: int -> (enc handle, unit) t
| Get_LSB_depth: (enc handle, int) t
| Set_expert_frame_duration: framesize -> (enc handle, unit) t
| Get_expert_frame_duration: (enc handle, framesize) t
| Set_prediction_disabled: bool -> (enc handle, unit) t
| Get_prediction_disabled: (enc handle, bool) t
end
type bigstring = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
type s16frame = (int, Bigarray.int16_signed_elt, Bigarray.c_layout) Bigarray.Array1.t
type f32frame = (int, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array1.t
module Encoder: sig
type t
type packet = [ `Packet of bigstring | `DTX ]
val recommended_max_size: int
val create:
?samplerate:int ->
?channels:[`mono | `stereo] ->
?application:application ->
unit ->
t result
val size: t -> int
val encode_blit:
t ->
?pcm_off:int ->
?duration:int ->
s16frame ->
?buf_off:int ->
?max_size:int ->
bigstring ->
packet result
val encode:
t ->
?off:int ->
?duration:int ->
?max_size:int ->
s16frame ->
packet result
val encode_blit_float:
t ->
?pcm_off:int ->
?duration:int ->
f32frame ->
?buf_off:int ->
?max_size:int ->
bigstring ->
(packet) result
val encode_float:
t ->
?off:int ->
?duration:int ->
?max_size:int ->
f32frame ->
packet result
val ctl: t -> ([`enc] handle, 'a) CTL.t -> 'a result
end
{
"name": "@discopotty/opus",
"version": "1.3.1",
"description": "OCaml libopus bindings",
"license": "BSD",
"esy": {
"build": "dune build -p opus",
"buildDev":
"dune build --promote-install-files --root . --only-package opus"
},
"dependencies": {
"@opam/conf-libopus": "*",
"@opam/ctypes": "0.18.0",
// FIXME wait for upstream (esy-opam-overrides)?
"@opam/ctypes-foreign": "<0.18.0",
"@opam/dune": "2.8.4",
"@opam/ocamlfind": "<1.9.0",
"@opam/ppx_cstubs": "0.6.1.1",
"ocaml": "~4.11.0"
},
"devDependencies": {
"@opam/merlin": "*",
"@opam/ocaml-lsp-server": "*",
"@opam/ocamlformat": "0.17.0",
"@opam/odoc": "*"
},
"resolutions": {
"@opam/conf-pkg-config": "1.3",
"@opam/conf-libopus": {
"source": "link:../esy-libopus/conf-libopus.opam",
"override": { "dependencies": { "esy-libopus": "../esy-libopus" } }
}
}
}