Skip to content

Commit 3995bb5

Browse files
authored
Wasm_of_ocaml support (#11093)
wasm_of_ocaml mode support Signed-off-by: Jérôme Vouillon <[email protected]>
1 parent 0d02468 commit 3995bb5

File tree

125 files changed

+1727
-359
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+1727
-359
lines changed

.github/workflows/workflow.yml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,91 @@ jobs:
190190
# We disable the Dune cache when running the tests
191191
DUNE_CACHE: disabled
192192

193+
wasm:
194+
name: Wasm_of_ocaml
195+
runs-on: ubuntu-latest
196+
steps:
197+
- name: Install Node
198+
uses: actions/setup-node@v4
199+
with:
200+
node-version: latest
201+
202+
- name: Restore Cached Binaryen
203+
id: cache-binaryen
204+
uses: actions/cache/restore@v4
205+
with:
206+
path: binaryen
207+
key: ${{ runner.os }}-binaryen-version_119
208+
209+
- name: Checkout Binaryen
210+
if: steps.cache-binaryen.outputs.cache-hit != 'true'
211+
uses: actions/checkout@v4
212+
with:
213+
repository: WebAssembly/binaryen
214+
path: binaryen
215+
submodules: true
216+
ref: version_119
217+
218+
- name: Install Ninja
219+
if: steps.cache-binaryen.outputs.cache-hit != 'true'
220+
run: sudo apt-get install ninja-build
221+
222+
- name: Build Binaryen
223+
if: steps.cache-binaryen.outputs.cache-hit != 'true'
224+
working-directory: ./binaryen
225+
run: |
226+
cmake -G Ninja .
227+
ninja
228+
229+
- name: Cache Binaryen
230+
if: steps.cache-binaryen.outputs.cache-hit != 'true'
231+
uses: actions/cache/save@v4
232+
with:
233+
path: binaryen
234+
key: ${{ runner.os }}-binaryen-version_119
235+
236+
- name: Set Binaryen's Path
237+
run: |
238+
echo "$GITHUB_WORKSPACE/binaryen/bin" >> $GITHUB_PATH
239+
240+
- name: Checkout Code
241+
uses: actions/checkout@v4
242+
with:
243+
path: dune
244+
245+
- name: Use OCaml 4.14.x
246+
uses: ocaml/setup-ocaml@v3
247+
with:
248+
ocaml-compiler: 4.14.x
249+
250+
- name: Update Dune
251+
working-directory: ./dune
252+
run: opam pin add -n dune . --with-version 3.17.0
253+
254+
- name: Checkout Wasm_of_ocaml
255+
uses: actions/checkout@v4
256+
with:
257+
repository: ocaml-wasm/wasm_of_ocaml
258+
ref: wasm-dune
259+
path: wasm_of_ocaml
260+
261+
- name: Install Wasm_of_ocaml
262+
working-directory: ./wasm_of_ocaml
263+
run: |
264+
opam pin add -n . --with-version `< VERSION`
265+
opam install wasm_of_ocaml-compiler
266+
267+
- name: Set Git User
268+
run: |
269+
git config --global user.name github-actions[bot]
270+
git config --global user.email github-actions[bot]@users.noreply.github.com
271+
- name: Run Tests
272+
working-directory: ./dune
273+
run: opam exec -- make test-wasm
274+
env:
275+
# We disable the Dune cache when running the tests
276+
DUNE_CACHE: disabled
277+
193278
monorepo_benchmark_test:
194279
name: Build monorepo benchmark docker image
195280
runs-on: ubuntu-latest

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ test-windows: $(BIN)
8989
test-js: $(BIN)
9090
$(BIN) build @runtest-js
9191

92+
test-wasm: $(BIN)
93+
DUNE_WASM_TEST=enable $(BIN) build @runtest-wasm
94+
9295
test-coq: $(BIN)
9396
DUNE_COQ_TEST=enable $(BIN) build @runtest-coq
9497

bin/printenv.ml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,25 @@ let dump sctx ~dir =
2727
|> Action_builder.of_memo
2828
>>= Dune_rules.Menhir_env.dump
2929
and+ coq_dump = Dune_rules.Coq.Coq_rules.coq_env ~dir >>| Dune_rules.Coq.Coq_flags.dump
30-
and+ jsoo_dump =
30+
and+ jsoo_js_dump =
3131
let module Js_of_ocaml = Dune_rules.Js_of_ocaml in
32-
let* jsoo = Action_builder.of_memo (Dune_rules.Jsoo_rules.jsoo_env ~dir) in
33-
Js_of_ocaml.Flags.dump jsoo.flags
32+
let* jsoo = Action_builder.of_memo (Dune_rules.Jsoo_rules.jsoo_env ~dir ~mode:JS) in
33+
Js_of_ocaml.Flags.dump ~mode:JS jsoo.flags
34+
and+ jsoo_wasm_dump =
35+
let module Js_of_ocaml = Dune_rules.Js_of_ocaml in
36+
let* jsoo = Action_builder.of_memo (Dune_rules.Jsoo_rules.jsoo_env ~dir ~mode:Wasm) in
37+
Js_of_ocaml.Flags.dump ~mode:Wasm jsoo.flags
3438
in
3539
let env =
36-
List.concat [ o_dump; c_dump; link_flags_dump; menhir_dump; coq_dump; jsoo_dump ]
40+
List.concat
41+
[ o_dump
42+
; c_dump
43+
; link_flags_dump
44+
; menhir_dump
45+
; coq_dump
46+
; jsoo_js_dump
47+
; jsoo_wasm_dump
48+
]
3749
in
3850
Super_context.context sctx |> Context.name, env
3951
;;

doc/changes/11093.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Wasm_of_ocaml support (#11093, @vouillon)

doc/howto/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ These guides will help you use Dune's features in your project.
1515
../sites
1616
../instrumentation
1717
../jsoo
18+
../wasmoo
1819
../melange
1920
../virtual-libraries
2021
../tests

doc/reference/dune/env.rst

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,24 @@ Fields supported in ``<settings>`` are:
4949
or not where ``<mode>`` is either ``no``, ``file`` (to generate sourcemap in a ``.map`` file next the the generated javascript file) or ``inline`` (to inline the sourcemap at the end of the generated JavaScript file).
5050

5151
- ``(js_of_ocaml (runtest_alias <alias-name>))`` specifies the alias under which
52-
:ref:`inline_tests` and tests (:ref:`tests-stanza`) run for the `js` mode.
52+
:ref:`inline_tests` and tests (:ref:`tests-stanza`) run for the ``js`` mode.
53+
54+
- ``(js_of_ocaml (enabled_if <blang expression>))`` specifies whether the ``js`` mode is enabled. It is enabled by default.
55+
56+
- ``(wasm_of_ocaml (flags <flags>)(build_runtime <flags>)(link_flags <flags>))``
57+
specifies ``wasm_of_ocaml`` flags. See :ref:`wasmoo-field` for more details.
58+
59+
- ``(wasm_of_ocaml (compilation_mode <mode>))`` controls whether to use separate
60+
compilation or not where ``<mode>`` is either ``whole_program`` or
61+
``separate``.
62+
63+
- ``(wasm_of_ocaml (sourcemap <mode>))`` controls whether to generate sourcemap
64+
or not where ``<mode>`` is either ``no``, ``file`` (to generate sourcemap in a ``.map`` file next the the generated javascript file) or ``inline`` (to inline the sourcemap at the end of the generated JavaScript file).
65+
66+
- ``(wasm_of_ocaml (runtest_alias <alias-name>))`` specifies the alias under which
67+
:ref:`inline_tests` and tests (:ref:`tests-stanza`) run for the ``wasm`` mode.
68+
69+
- ``(wasm_of_ocaml (enabled_if <blang expression>))`` specifies whether the ``wasm`` mode is enabled. It is enabled by default.
5370

5471
- ``(binaries <binaries>)``, where ``<binaries>`` is a list of entries of the
5572
form ``(<filepath> as <name>)``. ``(<filepath> as <name>)`` makes the binary

doc/reference/dune/executable.rst

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ executable stanzas is as follows:
1414
There can be additional modules in the current directory; you only need to
1515
specify the entry point. Given an ``executable`` stanza with ``(name <name>)``,
1616
Dune will know how to build ``<name>.exe``. If requested, it will also know how
17-
to build ``<name>.bc`` and ``<name>.bc.js`` (Dune 2.0 and up also need specific
18-
configuration (see the ``modes`` optional field below)).
17+
to build ``<name>.bc``, ``<name>.bc.js`` and ``<name>.bc.wasm.js`` (Dune 2.0
18+
and up also needs specific configuration (see the ``modes`` optional field
19+
below)).
1920

2021
``<name>.exe`` is a native code executable, ``<name>.bc`` is a bytecode
21-
executable which requires ``ocamlrun`` to run, and ``<name>.bc.js`` is a
22-
JavaScript generated using ``js_of_ocaml``.
22+
executable which requires ``ocamlrun`` to run, ``<name>.bc.js`` is a
23+
JavaScript generated using ``js_of_ocaml``, and ``<name>.bc.wasm.js`` is a
24+
Wasm loader script generated using ``wasm_of_ocaml`` (the Wasm modules are included in
25+
directory ``<name>.bc.wasm.assets``).
2326

2427
Please note: in case native compilation is not available, ``<name>.exe`` will be
2528
a custom bytecode executable, in the sense of ``ocamlc -custom``. This means
@@ -91,6 +94,8 @@ files for executables. See
9194

9295
- ``js_of_ocaml``: See the section about :ref:`jsoo-field`
9396

97+
- ``wasm_of_ocaml``: See the section about :ref:`wasmoo-field`
98+
9499
- ``flags``, ``ocamlc_flags``, and ``ocamlopt_flags``: See
95100
:doc:`/concepts/ocaml-flags`.
96101

@@ -165,6 +170,7 @@ available.
165170
non-OCaml application.
166171
- ``js`` for producing JavaScript from bytecode executables, see
167172
:doc:`/reference/dune-project/explicit_js_mode`.
173+
- ``wasm`` for producing JavaScript from bytecode executables.
168174
- ``plugin`` for producing a plugin (``.cmxs`` if native or ``.cma`` if
169175
bytecode).
170176

@@ -186,6 +192,7 @@ Additionally, you can use the following shorthands:
186192
- ``byte`` for ``(byte exe)``
187193
- ``native`` for ``(native exe)``
188194
- ``js`` for ``(byte js)``
195+
- ``wasm`` for ``(byte wasm)``
189196
- ``plugin`` for ``(best plugin)``
190197

191198
For instance, the following ``modes`` fields are all equivalent:
@@ -216,6 +223,7 @@ The extensions for the various linking modes are chosen as follows:
216223
.. (native/best shared_object) %{ext_dll}
217224
.. c .bc.c
218225
.. js .bc.js
226+
.. wasm .bc.wasm.js
219227
.. (best plugin) %{ext_plugin}
220228
.. (byte plugin) .cma
221229
.. (native plugin) .cmxs
@@ -264,14 +272,38 @@ options using ``(js_of_ocaml (<js_of_ocaml-options>))``.
264272
- ``(sourcemap <config>)`` where ``<config>>`` is one of ``no``, ``file`` or ``inline``.
265273
This is only available inside ``executable`` stanzas.
266274

275+
- ``(enabled_if <blang expression>)`` to specify whether the ``js`` mode is enabled. It is enabled by default.
276+
This is only available inside ``executable`` stanzas.
277+
267278
``<flags>`` is specified in the :doc:`/reference/ordered-set-language`.
279+
``<blang expression>`` is specified using the :doc:`/reference/boolean-language`,
268280

269281
The default values for ``flags``, ``compilation_mode`` and ``sourcemap`` depend on the selected build profile. The
270282
build profile ``dev`` (the default) will enable inline sourcemap, separate compilation and pretty
271283
JavaScript output.
272284

273285
See :ref:`jsoo` for more information.
274286

287+
.. _wasmoo-field:
288+
289+
wasm_of_ocaml
290+
~~~~~~~~~~~~~
291+
292+
In ``library`` and ``executable`` stanzas, you can specify ``wasm_of_ocaml``
293+
options using ``(wasm_of_ocaml (<wasm_of_ocaml-options>))``.
294+
295+
``<wasm_of_ocaml-options>`` are all optional. They are the same as the ``<js_of_ocaml-options>`` above plus:
296+
297+
- ``(wasm_files (<files-list>))`` to specify ``wasm_of_ocaml``
298+
Wasm runtime files.
299+
300+
For the ``(sourcemap <config>)`` option, ``<config>`` must be one of ``no`` or ``inline``. Source maps are put within the ``.bc.wasm.assets`` directory.
301+
302+
The default values for ``flags``, ``compilation_mode`` and ``sourcemap`` depend on the selected build profile. The
303+
build profile ``dev`` (the default) will enable sourcemaps, separate compilation and pretty Wasm output.
304+
305+
See :ref:`wasmoo` for more information.
306+
275307
executables
276308
-----------
277309

doc/reference/dune/library.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ order to declare a multi-directory library, you need to use the
213213

214214
Sets options for JavaScript compilation, see :ref:`jsoo-field`.
215215

216+
.. describe:: (wasm_of_ocaml ...)
217+
218+
Sets options for JavaScript compilation, see :ref:`wasmoo-field`.
219+
216220
.. describe:: (flags ...)
217221

218222
See :doc:`/concepts/ocaml-flags`.

doc/tests.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,15 @@ field. Available modes are:
258258
- ``best`` for running tests in native mode with fallback to byte code,
259259
if native compilation is not available
260260
- ``js`` for running tests in JavaScript using Node.js
261+
- ``wasm`` for running tests in Wasm using Node.js
261262

262263
For instance:
263264

264265
.. code:: ocaml
265266
266267
(library
267268
(name foo)
268-
(inline_tests (modes byte best js))
269+
(inline_tests (modes byte best js wasm))
269270
(preprocess (pps ppx_expect)))
270271
271272

doc/wasmoo.rst

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
.. _wasmoo:
2+
3+
***************************************
4+
Wasm Compilation With Wasm_of_ocaml
5+
***************************************
6+
7+
.. TODO(diataxis)
8+
9+
This is an how-to guide.
10+
11+
Wasm_of_ocaml_ is a compiler from OCaml to WebAssembly (Wasm for
12+
short). The compiler works by translating OCaml bytecode to Wasm code.
13+
The compiler can currently be installed from [its Github repository](https://github.com/ocaml-wasm/wasm_of_ocaml).
14+
15+
Compiling to Wasm
16+
=================
17+
18+
Dune has full support for building wasm_of_ocaml libraries and executables transparently.
19+
There's no need to customise or enable anything to compile OCaml
20+
libraries/executables to Wasm.
21+
22+
To build a Wasm executable, just define an executable as you would normally.
23+
Consider this example:
24+
25+
.. code:: console
26+
27+
$ echo 'print_endline "hello from wasm"' > foo.ml
28+
29+
With the following ``dune`` file:
30+
31+
.. code:: dune
32+
33+
(executable (name foo) (modes wasm))
34+
35+
And then request the ``.wasm.js`` target:
36+
37+
.. code:: console
38+
39+
$ dune build ./foo.bc.wasm.js
40+
$ node _build/default/foo.bc.wasm.js
41+
hello from wasm
42+
43+
If you're using the js_of_ocaml syntax extension, you must remember to add the
44+
appropriate PPX in the ``preprocess`` field:
45+
46+
.. code:: dune
47+
48+
(executable
49+
(name foo)
50+
(modes wasm)
51+
(preprocess (pps js_of_ocaml-ppx)))
52+
53+
Selective Compilation
54+
=====================
55+
56+
The ``js`` and ``wasm`` modes can be selectively disabled using the ``(js_of_ocaml (enabled_if ...))`` and ``(wasm_of_ocaml (enabled_if ...))`` options. This allows for instance to generate one, or the other dependings on a profile:
57+
58+
.. code:: dune
59+
60+
(env
61+
(js-only
62+
(wasm_of_ocaml
63+
(enabled_if false)))
64+
(wasm-only
65+
(js_of_ocaml
66+
(enabled_if false))))
67+
68+
To be able to invoke the generated code using the same JavaScript script name in all cases, you can add a rule to copy the Wasm launcher script when the js_of_ocaml compilation is disabled.
69+
70+
.. code:: dune
71+
72+
(rule
73+
(action
74+
(copy foo.bc.wasm.js foo.bc.js))
75+
(enabled_if
76+
(= %{profile} wasm-only)))
77+
78+
Separate Compilation
79+
====================
80+
81+
Dune supports two modes of compilation:
82+
83+
- Direct compilation of a bytecode program to Wasm. This mode allows
84+
wasm_of_ocaml to perform whole-program deadcode elimination and whole-program
85+
inlining.
86+
87+
- Separate compilation, where compilation units are compiled to Wasm
88+
separately and then linked together. This mode is useful during development as
89+
it builds more quickly.
90+
91+
The separate compilation mode will be selected when the build profile
92+
is ``dev``, which is the default. It can also be explicitly specified
93+
in an ``env`` stanza (see :doc:`/reference/dune/env`) or per executable
94+
inside ``(wasm_of_ocaml (compilation_mode ...))`` (see :doc:`/reference/dune/executable`)
95+
96+
Sourcemap
97+
=========
98+
99+
Wasm_of_ocaml can generate sourcemaps for the generated Wasm code.
100+
By default, they are generated when using the ``dev`` build profile and are not generated otherwise.
101+
The behavior can explicitly be specified in an ``env`` stanza (see :doc:`/reference/dune/env`)
102+
or per executable inside ``(wasm_of_ocaml (sourcemap ...))`` (see :doc:`/reference/dune/executable`)
103+
104+
.. _wasm_of_ocaml: https://github.com/ocaml-wasm/wasm_of_ocaml

0 commit comments

Comments
 (0)