From 1f3ecf646d18c90a0406c0683131f216cfefeb17 Mon Sep 17 00:00:00 2001 From: hhugo Date: Fri, 4 Nov 2022 16:34:42 +0100 Subject: [PATCH] Doc: document findlib interaction (#1323) --- manual/linker.wiki | 14 ++-- manual/menu.wiki | 1 + manual/overview.wiki | 2 +- manual/runtime-files.wiki | 115 +++++++++++++++++++++++++++++++ manual/separate-compilation.wiki | 15 +--- 5 files changed, 124 insertions(+), 23 deletions(-) create mode 100644 manual/runtime-files.wiki diff --git a/manual/linker.wiki b/manual/linker.wiki index 0820d14404..faab189fd9 100644 --- a/manual/linker.wiki +++ b/manual/linker.wiki @@ -2,10 +2,10 @@ 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) @@ -13,12 +13,8 @@ Pass the JavaScript file (must have a ".js" extension) js_of_ocaml jsfile.js a.byte >> -Or load it from a findlib package -<> -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 <> 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. diff --git a/manual/menu.wiki b/manual/menu.wiki index bf0cfdab57..ea21b649ca 100644 --- a/manual/menu.wiki +++ b/manual/menu.wiki @@ -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]] diff --git a/manual/overview.wiki b/manual/overview.wiki index dfb287d109..56449ebba2 100644 --- a/manual/overview.wiki +++ b/manual/overview.wiki @@ -47,7 +47,7 @@ For alternatives, see <>. === with ocamlbuild and oasis === Js_of_ocaml also provide an ocamlbuild plugin. - See <>. + 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. diff --git a/manual/runtime-files.wiki b/manual/runtime-files.wiki new file mode 100644 index 0000000000..7da9d72a2e --- /dev/null +++ b/manual/runtime-files.wiki @@ -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. \ No newline at end of file diff --git a/manual/separate-compilation.wiki b/manual/separate-compilation.wiki index ff443c4b05..9d2479a3b3 100644 --- a/manual/separate-compilation.wiki +++ b/manual/separate-compilation.wiki @@ -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 <> chapter for how to +discover these files. === 2. Build compilation units