Skip to content

Commit

Permalink
Doc: document findlib interaction (#1323)
Browse files Browse the repository at this point in the history
  • Loading branch information
hhugo authored Nov 4, 2022
1 parent 48dd3c2 commit 1f3ecf6
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 23 deletions.
14 changes: 5 additions & 9 deletions manual/linker.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,19 @@
The Js_of_ocaml compiler accepts JavaScript files provided on the command-line.
The main purpose is to provide (external) primitives needed by the bytecode program.

Most of the primitives from the standard library are already implemented and loaded by default (located in "runtime.js").
Most of the primitives from the standard library are already implemented and loaded by default.

Additionally, some other primitives are installed but not loaded by default:
* "+toplevel.js" : when compiling toplevel
Additionally, some other primitives are available but not loaded by default:
* "+toplevel.js" and "+dynlink.js" when compiling toplevel and/or using dynlink.

== Command-line
Pass the JavaScript file (must have a ".js" extension)
<<code |
js_of_ocaml jsfile.js a.byte
>>

Or load it from a findlib package
<<code |
js_of_ocaml +mypackage/jsfile.js a.byte
>>
The file **jsfile.js** will be looked up inside **mypackage** lib directory.
When no package is provided, the compiler will look inside js_of_ocaml-compiler lib directory.
See the <<a_manual chapter="runtime-files" |runtime files>> chapter for how to
discover runtime files.

== Provide your own JavaScript
You may need to provide extra JavaScript files to provide missing primitives or to override existing ones.
Expand Down
1 change: 1 addition & 0 deletions manual/menu.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
==[[tailcall|About tailcall optimization]]

=Misc
==[[runtime-files|How to look up runtime files]]
==[[debug|How to debug a program]]
==[[contribute|How to contribute]]
==[[performances|Performances]]
Expand Down
2 changes: 1 addition & 1 deletion manual/overview.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ For alternatives, see <<a_manual chapter="install" |Install>>.

=== with ocamlbuild and oasis ===
Js_of_ocaml also provide an ocamlbuild plugin.
See <<a_api subproject="js_of_ocaml-ocamlbuild"|module Ocamlbuild_js_of_ocaml>>.
See [[https://github.com/ocsigen/js_of_ocaml-ocamlbuild/blob/master/ocamlbuild_js_of_ocaml.mli|js_of_ocaml-ocamlbuild>>.
=== with dune ===
Dune has native support for js_of_ocaml.
Expand Down
115 changes: 115 additions & 0 deletions manual/runtime-files.wiki
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
= Runtime files =

For compiling a bytecode executable to JavaScript, one often need to pass
JavaScript runtime files for some OCaml libraries used by the
executable. Tracking the required runtime files is done using the de-facto
standard for library management in OCaml, Findlib.


== Listing js runtime files

To list all JavaScript runtime files for a set of libraries:

{{{
ocamlfind query -format "%+(jsoo_runtime)" -r LIB1 LIB2 ... | grep -v "^$"
}}}

For example, for **base** and **time_now**

{{{
$ ocamlfind query -format "%+(jsoo_runtime)" -r base time_now | grep -v "^$"
~/.opam/4.14.0/lib/base/base_internalhash_types/runtime.js
~/.opam/4.14.0/lib/base/runtime.js
~/.opam/4.14.0/lib/time_now/runtime.js
}}}

Here is minimal example of manually compiling a single ml file program:
{{{
$ export LIBS=base,time_now
$ ocamlfind ocamlc -package $LIBS -linkpkg main.ml -o main.byte
$ js_of_ocaml $(ocamlfind query -format "%+(jsoo_runtime)" -r $LIBS) main.byte
}}}

== Declaring runtime JavaScript files inside a META file

The **jsoo_runtime** variable is used to declare one or more runtime files.
Files must be coma-separated and should be plain names relative to the package directory.

For example, to declare that **mypackage.sublib** requires the file **mypackage/subdir/runtime.js**
{{{
cat mypackage/META
package "sublib" (
directory = "subdir"
jsoo_runtime = "runtime.js"
)
}}}

While the mechanism allows arbitrary naming for the javascript files,
if there is only one file, we suggest naming it **runtime.js** by
convention.

== The old deprecated way

Before dune and its native support for js_of_ocaml, the (hacky) way
to rely on Findlib was to use a **linkopts** variable with a **javascript**
predicate {{{linkopts(javascript)}}} and have js_of_ocaml be responsible for
looking up the files in the right directory.

This approach is not very satisfying:
* It makes it harder for a build system to know the set of dependencies.
* The js_of_ocaml compiler needs to perform findlib resolution itself.
=== Listing linkopts

To list all {{{linkopts(javascript)}}} for a set of libraries:

{{{
ocamlfind query -o-format -r -predicates javascript LIB1 LIB2 ...
}}}

For example, for **base** and **time_now**

{{{
$ ocamlfind query -o-format -r -predicates javascript base time_now
+base/base_internalhash_types/runtime.js
+base/runtime.js
+time_now/runtime.js
}}}

=== Declaring runtime JavaScript files inside META files

The content of {{{linkopts(javascript)}}} is given directly to the
js_of_ocaml compiler. To be able reference files independently of the
installation path, we rely on js_of_ocaml's findlib support (see Command-Line findlib support below).

For example, to declare that **mypackage.sublib** requires the file **mypackage/subdir/runtime.js**

{{{
cat mypackage/META
package "sublib" (
directory = "subdir"
linkopts(javascript) = "+mypackage/sublib/runtime.js"
)
}}}

== Command line findlib support (deprecated)
If js_of_ocaml is compiled with findlib support, one can use the
following syntax to reference JavaScript files:
* {{{ +{findlib-package}/{javascript-file} }}}
* {{{ +{javascript-file} }}}
The file **javascript-file** will be looked up inside the **findlib-package** lib directory.

When no package is provided, the compiler will look inside js_of_ocaml-compiler lib directory.

For example, if findlib install all libraries inside ${LIBDIR}:
* {{{+mypackage/jsfile.js}}} resolves to {{{${LIBDIR}/mypackage/jsfile.js}}}
* {{{+mypackage/dir/jsfile.js}}} resolves to {{{${LIBDIR}/mypackage/dir/jsfile.js}}}
* {{{+toplevel.js}}} resolves to {{{${LIBDIR}/js_of_ocaml-compiler/jsfile.js}}}
== Compatibility

**dune** generate META files that are usable with the old deprecated
way. However, it only uses **jsoo_runtime** to look up information.

**js_of_ocaml-ocamlbuild** uses **jsoo_runtime** by default starting with version 5.0.
15 changes: 2 additions & 13 deletions manual/separate-compilation.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,8 @@ Additional runtime files are sometime needed and can be passed on the
command line. In particular, some packages/libraries come with their
own runtime file.

As an example, compiling a program that has a dependency on {{{base}}}
will require the {{{runtime.js}}}} file provided by base.

{{{
js_of_ocaml --runtime-only -o my-runtime.js PATH_TO_BASE_LIB/runtime.js dummy
}}}

If js_of_ocaml is compiled with findlib support, one can also use the
following syntax {{{ +{findlib-package}/{javascript-file} }}}.

{{{
js_of_ocaml --runtime-only -o my-runtime.js +base/runtime.js dummy
}}}
See the <<a_manual chapter="runtime-files" |runtime files>> chapter for how to
discover these files.

=== 2. Build compilation units

Expand Down

0 comments on commit 1f3ecf6

Please sign in to comment.