diff --git a/CHANGES.md b/CHANGES.md index 8ffd45871f..f93122abdc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,7 @@ * Runtime: change Sys.os_type on windows (Cygwin -> Win32) * Runtime: backtraces are really expensive, they need to be be explicitly requested at compile time (--enable with-js-error) or at startup (OCAMLRUNPARAM=b=1) +* Runtime: allow dynlink of precompiled js with separate compilation (#1676) * Lib: Modify Typed_array API for compatibility with WebAssembly diff --git a/compiler/tests-dynlink-js/dune b/compiler/tests-dynlink-js/dune index 064ea7b5a8..37a0f7561f 100644 --- a/compiler/tests-dynlink-js/dune +++ b/compiler/tests-dynlink-js/dune @@ -2,12 +2,48 @@ (name main) (modules main) (libraries js_of_ocaml) - (modes byte)) + (link_flags + (:standard -linkall)) + ;; Until dune is fixed https://github.com/ocaml/dune/pull/10935 + (js_of_ocaml + (flags + (:standard) + --linkall + (:include effects_flags.sexp)) + (build_runtime_flags + (:standard) + (:include effects_flags.sexp)) + (link_flags (:standard))) + (modes js byte)) + +(executable + (name effects_flags) + (modules effects_flags)) + +(rule + (target effects_flags.sexp) + (action + (with-stdout-to + %{target} + (run ./effects_flags.exe sexp %{profile})))) + +(rule + (target effects_flags.txt) + (action + (with-stdout-to + %{target} + (run ./effects_flags.exe txt %{profile})))) (rule (target main.js) (action - (run %{bin:js_of_ocaml} --linkall -o %{target} %{dep:main.bc}))) + (run + %{bin:js_of_ocaml} + --linkall + %{read-strings:effects_flags.txt} + -o + %{target} + %{dep:main.bc}))) (rule (target plugin.cmo) @@ -17,17 +53,52 @@ (rule (target plugin.js) (action - (run %{bin:js_of_ocaml} %{dep:./plugin.cmo}))) + (run + %{bin:js_of_ocaml} + %{read-strings:effects_flags.txt} + %{dep:./plugin.cmo}))) + +(rule + (target plugin2.cma) + (action + (run + %{bin:ocamlc} + -a + %{dep:./plugin2a.ml} + %{dep:./plugin2b.ml} + -o + plugin2.cma))) + +(rule + (target plugin2.js) + (action + (run + %{bin:js_of_ocaml} + %{read-strings:effects_flags.txt} + %{dep:./plugin2.cma}))) (rule (target main.out) - (deps plugin.js) + (deps plugin.js plugin2.js) (action (with-outputs-to %{target} (run %{bin:node} %{dep:./main.js})))) +(rule + (target main.out2) + (deps plugin.js plugin2.js) + (action + (with-outputs-to + %{target} + (run %{bin:node} %{dep:./main.bc.js})))) + (rule (alias runtest) (action (diff main.out.expected main.out))) + +(rule + (alias runtest) + (action + (diff main.out.expected main.out2))) diff --git a/compiler/tests-dynlink-js/effects_flags.ml b/compiler/tests-dynlink-js/effects_flags.ml new file mode 100644 index 0000000000..c0fce23c94 --- /dev/null +++ b/compiler/tests-dynlink-js/effects_flags.ml @@ -0,0 +1,19 @@ +let enable b n = + let f = if b then "--enable" else "--disable" in + [ f; n ] + +let () = + let major = String.split_on_char '.' Sys.ocaml_version |> List.hd |> int_of_string in + let has_effect l = + match l with + | [ "using-effects" ] -> major >= 5 + | _ -> false + in + let aux l = enable (has_effect l) "effects" in + match Sys.argv |> Array.to_list |> List.tl with + | "txt" :: rest -> List.iter print_endline (aux rest) + | "sexp" :: rest -> + print_endline "("; + List.iter print_endline (aux rest); + print_endline ")" + | _ -> assert false diff --git a/compiler/tests-dynlink-js/main.ml b/compiler/tests-dynlink-js/main.ml index 98cf2f9a47..31825e4a26 100644 --- a/compiler/tests-dynlink-js/main.ml +++ b/compiler/tests-dynlink-js/main.ml @@ -5,3 +5,5 @@ let require s = Js.Unsafe.fun_call (Js.Unsafe.js_expr "require") [| Js.Unsafe.inject (Js.string s) |] let () = require "./plugin.js" + +let () = require "./plugin2.js" diff --git a/compiler/tests-dynlink-js/main.out.expected b/compiler/tests-dynlink-js/main.out.expected index ba390cb600..587f51d01e 100644 --- a/compiler/tests-dynlink-js/main.out.expected +++ b/compiler/tests-dynlink-js/main.out.expected @@ -1,2 +1,4 @@ hello plugin loaded +plugin 2a loaded +plugin 2b loaded diff --git a/compiler/tests-dynlink-js/plugin2a.ml b/compiler/tests-dynlink-js/plugin2a.ml new file mode 100644 index 0000000000..28d230b361 --- /dev/null +++ b/compiler/tests-dynlink-js/plugin2a.ml @@ -0,0 +1 @@ +let () = print_endline "plugin 2a loaded" diff --git a/compiler/tests-dynlink-js/plugin2b.ml b/compiler/tests-dynlink-js/plugin2b.ml new file mode 100644 index 0000000000..3c05267241 --- /dev/null +++ b/compiler/tests-dynlink-js/plugin2b.ml @@ -0,0 +1 @@ +let () = print_endline "plugin 2b loaded" diff --git a/runtime/stdlib.js b/runtime/stdlib.js index 3e878681cf..e537b382a8 100644 --- a/runtime/stdlib.js +++ b/runtime/stdlib.js @@ -150,11 +150,15 @@ var caml_global_data = [0]; //Requires: caml_jsstring_of_string function caml_build_symbols(symb) { var r = {}; + var max = -1; if (symb) { for (var i = 1; i < symb.length; i++) { - r[caml_jsstring_of_string(symb[i][1])] = symb[i][2]; + var idx = symb[i][2]; + max = Math.max(max, idx); + r[caml_jsstring_of_string(symb[i][1])] = idx; } } + r.next_idx = max + 1; return r; } @@ -173,7 +177,10 @@ function caml_register_global(n, v, name_opt) { var nid = caml_global_data.symidx[name]; if (nid >= 0) n = nid; else { - caml_failwith("caml_register_global: cannot locate " + name); + // The unit is unknown, this can happen when dynlinking a precompiled js, + // let's allocate a fresh idx. + var n = caml_global_data.symidx.next_idx++; + caml_global_data.symidx[name] = n; } } }