How to compile a file that uses the JsooTop module? - ocaml

I have this in a file named main.ml:
let () = JsooTop.initialize ()
I tried compiling the file using:
ocamlfind ocamlc -package js_of_ocaml -linkpkg -o main.byte main.ml
But this error appears:
File "main.ml", line 1, characters 9-27:
Error: Unbound module JsooTop
It appears that JsooTop is not present on my machine, so I ran opam install js_of_ocaml-toplevel, and tried compiling the file again using:
ocamlfind ocamlc -package js_of_ocaml -package js_of_ocaml-toplevel -linkpkg -o main.byte main.ml
js_of_ocaml main.byte
But I get warnings:
Warnings from ocamlfind:
findlib: [WARNING] Interface topdirs.cmi occurs in several directories: /usr/lib/ocaml, /usr/lib/ocaml/compiler-libs
Warnings from the js_of_ocaml executable:
There are some missing primitives
Dummy implementations (raising 'Failure' exception) will be used if they are not available at runtime.
You can prevent the generation of dummy implementations with the commandline option '--disable genprim'
Missing primitives provided by +dynlink.js:
caml_add_debug_info
caml_dynlink_add_primitive
caml_dynlink_get_current_libs
caml_dynlink_lookup_symbol
caml_dynlink_open_lib
caml_remove_debug_info
Missing primitives provided by +toplevel.js:
caml_get_current_environment
caml_get_section_table
caml_invoke_traced_function
caml_realloc_global
caml_reify_bytecode
caml_static_alloc
caml_static_free
caml_static_release_bytecode
caml_terminfo_setup
My question is: what is the proper way to compile a file that uses the JsooTop module?

First, make sure that the required OPAM packages are present:
opam install js_of_ocaml js_of_ocaml-toplevel
To build a program that uses the JsooTop module, compile the file in this way:
ocamlfind ocamlc -package js_of_ocaml -package js_of_ocaml-toplevel -linkpkg -o main.byte main.ml
js_of_ocaml --toplevel --dynlink +dynlink.js +toplevel.js main.byte
Note the inclusion of --toplevel, --dynlink, +dynlink.js, and +toplevel.js. The commands above will produce a JavaScript file named main.js.

Related

How to link OCaml object file with Core module?

I have simple program, which uses function from Core.Std module, e.g.:
open Core.Std
let _ = List.last [1;2;3]
I can compile and link it by ocamlfind or ocamlbuild:
ocamlfind ocamlc -package core -linkpkg -thread app.ml
ocamlbuild -use-ocamlfind -pkgs core -tag thread app.native
But I don't know how to compile and link such file using "normal" OCaml compiler:
ocamlc -c -I ~/.opam/system/lib/core_kernel/ -I ~/.opam/system/lib/core/ app.ml
ocamlc ~/.opam/system/lib/core_kernel/core_kernel.cma ~/.opam/system/lib/core/core.cma app.cmo
Last of above commands gives the following error:
File "_none_", line 1:
Error: Error on dynamically loaded library: /home/maciej/.opam/system/lib/stublibs/dllcore_kernel_stubs.so: /home/maciej/.opam/system/lib/stublibs/dllcore_kernel_stubs.so: undefined symbol: caml_ba_alloc
What am I doing wrong?
You can use ocamlfind ocamlc -only-show … to see the full command constructed by ocamlfind . Your error points towards some missing transitive dependencies of Core and an old version of OCaml and Core.

js_of_ocaml Camlp4 Parse error in type definition

I'm trying to build this program using js_of_ocaml. According to this answer, I've got the following line in my makefile
OCAMLC = ocamlfind ocamlc -package js_of_ocaml -package js_of_ocaml.syntax -syntax camlp4o -linkpkg -g -dtypes
However, when I try to build, I get the following error:
ocamlfind ocamlc -package js_of_ocaml -package js_of_ocaml.syntax -syntax camlp4o -linkpkg -g -dtypes -c types.ml
> File "types.ml", line 472, characters 11-12:
> Parse error: [type_longident] expected after ")" (in [type_ident_and_parameters])
> File "types.ml", line 1:
The offending line of the file is this:
type ('t,'v) parser = ('t list -> 'v -> unit) -> 't list -> unit
I'm still pretty new to OCaml, so I'm not totally sure what's going on.
What does the -syntax camlp4o do? What kinds of things in the source might I need to change to be compatible with js_of_ocaml?
camlp4o provides the same syntax as the vanilla OCaml syntax, but with slight incompatibility: parser is a special keyword in camlp4o. This is why parser is rejected if you use camlp4o syntax.
You can workaround this problem by renaming parser, or using PPX syntax extension of js_of_ocaml instead of CamlP4. Please check https://ocsigen.org/js_of_ocaml/api/Ppx_js for details of this newer syntax helper for js_of_ocaml.

OCaml: how to solve findlib warnings of multiple `cmi`s

Now I try to write a compiler using ocamlfind and some packages, especially ppx_sexp_conv with opam.
Somehow dependencies of ppx_sexp_conv require compiler-libs so the compilation option -I ~/.opam/VERSION/lib/compiler-libs is added when compiling files by ocamlfind ocamlc -package ppx_sexp_conv.
The problem is, compiler-libs includes very common name files like parsing.cmi, main.cmi, lexing.cmi.
This make conflicts of .cmi files and make many noisy warnings as follows:
$ ocamlfind ocamlc -package ppx_sexp_conv -c parser.mli
findlib: [WARNING] Interface main.cmi occurs in several directories: ., /home/nomaddo/.opam/4.02.3/lib/ocaml/compiler-libs
findlib: [WARNING] Interface lexer.cmi occurs in several directories: ., /home/nomaddo/.opam/4.02.3/lib/ocaml/compiler-libs
findlib: [WARNING] Interface topdirs.cmi occurs in several directories: /home/nomaddo/.opam/4.02.3/lib/ocaml/compiler-libs, /home/nomaddo/.opam/4.02.3/lib/ocaml
findlib: [WARNING] Interface parser.cmi occurs in several directories: ., /home/nomaddo/.opam/4.02.3/lib/ocaml/compiler-libs
```
Note that main.cmi, parsing.cmi, lexing.cmi and main.cmi exist in the same directory.
I believe that such file names are common and everybody want to use.
My question is, how to quiet such noisy warnings.
Thanks to them, it is hard to find more important warnings and errors immediately...
My environment: ocaml 4.02.3 with opam 1.2.2.
One way to suppress those warnings is to set findlib environment variable OCAMLFIND_IGNORE_DUPS_IN to /home/nomaddo/.opam/4.03.0/lib/ocaml/compiler-libs.
Here is an example with OCaml 4.03.0 and ppx_sexp_conv version 113.33.01+4.03.
parser.mli:
type t = int [##deriving sexp]
In shell, do the following
export OCAMLFIND_IGNORE_DUPS_IN=/home/nomaddo/.opam/4.03.0/lib/ocaml/compiler-libs
ocamlfind ocamlc -package ppx_sexp_conv -dsource -c parser.mli
You can see the .mli is preprocessed and no extra warning is emitted.
Reference:
findlib man page
Mantis 6754

Make compatible ocaml, camlp4, ppx, node, js_of_ocaml, ocamlbuild

After installing npm and node, compiling OCaml files with js_of_ocaml gave errors, thus I did opam switch reinstall system:
:testweb $ opam switch reinstall system
Your system compiler has been changed. Do you want to upgrade your OPAM installation ? [Y/n] y
=-=- Upgrading system -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 🐫
[WARNING] base-ocamlbuild.base is not available because it requires OCaml >= 3.10 & < 4.03. Skipping.
[WARNING] camlp4.4.02+system is not available because your system doesn't comply with preinstalled &
ocaml-version >= "4.02" & ocaml-version < "4.03". Skipping.
[WARNING] ppx_tools.4.02.3 is not available because your system doesn't comply with ocaml-version >=
"4.02.0" & ocaml-version < "4.03.0". Skipping.
The following dependencies couldn't be met:
- deriving -> camlp4
Your request can't be satisfied:
- camlp4 is not available because your system doesn't comply with ocaml-version >= "4.04".
No solution found, exiting
The former package state can be restored with opam switch import "/Users/softtimur/.opam/backup/state-20160418124642.export" --switch system
Then, i realized ocamlfind did not work anymore:
:testweb $ ocamlfind ocamlc -package js_of_ocaml.ppx -linkpkg cubes.ml -o T
-bash: /Users/softtimur/.opam/system/bin/ocamlfind: No such file or directory
PS: node --version gives v6.1.0; npm --version gives 3.8.6; ocaml -version gives The OCaml toplevel, version 4.03.0.
js_of_ocaml --version was 2.7, but after the opam swtich reinstall system, it gives -bash: /Users/softtimur/.opam/system/bin/js_of_ocaml: No such file or directory.
Does anyone know what to do to make all these packages compatible?
Earlier: Here were the compilation errors after installing npm and node, and before doing opam switch reinstall system:
:testweb $ ocamlfind ocamlc -package js_of_ocaml.ppx -linkpkg cubes.ml -o T
Failure("Ast_mapper: OCaml version mismatch or malformed input")
File "cubes.ml", line 1:
Error: Error while running external preprocessor
Command line: /Users/softtimur/.opam/system/lib/js_of_ocaml/./ppx_js '/var/folders/fn/0rmvqqbs4k76lg5g6b7kll100000gn/T/camlppxffe989' '/var/folders/fn/0rmvqqbs4k76lg5g6b7kll100000gn/T/camlppx02e06a'
Another way also gave an error:
:testweb $ ocamlfind ocamlc -package js_of_ocaml -syntax camlp4o -package js_of_ocaml.syntax -linkpkg -o cubes.byte cubes.ml
Fatal error: unknown C primitive `caml_is_printable'
File "cubes.ml", line 1:
Error: Error while running external preprocessor
Command line: camlp4 '-I' '/usr/local/lib/ocaml/camlp4' '-I' '/Users/softtimur/.opam/system/lib/js_of_ocaml' '-parser' 'o' '-parser' 'op' '-printer' 'p' 'pa_js.cmo' 'cubes.ml' > /var/folders/fn/0rmvqqbs4k76lg5g6b7kll100000gn/T/ocamlpp8b28e8
Initially:
My initial goal is to write and compile cubes.ml such that 1) it wraps an OCaml function to make a JS function that can be called in web; 2) the OCaml function and the bytecode can be tested in a command line under Linux.
cubes.ml is as follows:
let () =
let oneArgument (a: int) = a + 100 in
Js.Unsafe.global##.jsOneArgument := Js.wrap_callback oneArgument;
print_string "hello\n";
exit 0
Then, ocamlfind ocamlc -package js_of_ocaml.ppx -linkpkg cubes.ml -o T should generate T such that ./T should return hello. And js_of_ocaml T -o cubes.js should generate cubes.js such that the function jsOneArgument of cubes.js can well be called by other JS or HTML files.
Before I messed up the packages, ./T returned Unimplemented Javascript primitive caml_pure_js_expr!, that is why i installed npm, node, etc...
I switched back to OCaml 4.02.3:
opam switch 4.02.3
Then,
eval `opam config env`
Then,
opam install ppx_tools js_of_ocaml
As a result, ocamlfind ocamlc -package js_of_ocaml.ppx -linkpkg cubes.ml -o T generates T, and js_of_ocaml T -o cubes.js generates cubes.js. node cubes.js does return hello.
However, ./T still returns Unimplemented Javascript primitive caml_pure_js_expr!, I am going to open another post for that...

How to use modules with js_of_ocaml?

I am currently working on a website project written in OCaml and compiled to javascript using js_of_ocaml. It works pretty well as long as I have only one source file using the command ocamlfind ocamlc -package js_of_ocaml -package js_of_ocaml.syntax -syntax camlp4o -linkpkg -o file.byte file.ml but I would like to include several modules in my project. How can I do that ?
The other modules are actually a lexer and a parser poduced by ocamllex and menhir. I have read a tutorial on how to use ocamllex and menhir with js_of_ocaml but it makes wrong assumptions on where js_of_ocaml is installed (I installed it with opam) and it uses ocamlbuild and I want to know how to do it by hand without using an automated tool such as ocamlbuild.
I found the solution by trying to understand the makefiles for the official examples.
Here is my Makefile :
OBJS=file1.cmo file2.cmo file3.cmo
NAME=projectname
OCAMLC=ocamlfind ocamlc -package js_of_ocaml -package js_of_ocaml.syntax -syntax camlp4o
$(NAME).byte: $(OBJS)
$(OCAMLC) -linkpkg -o $# $(OBJS)
$(NAME).js: $(NAME).byte
js_of_ocaml $<
%.cmo: %.ml
$(OCAMLC) -c $<
...
ocamlbuild keeps a log of the operations it performs. After an ocamlbuild call, look at _build/_log and you will see all the commands that it has invoked, with full arguments etc. That's probably the easiest way for you to figure how to do it by hand.
(Regarding +site-lib assumptions and OPAM, that's something you should report to the authors of the tutorial, they'll want to make sure that it also works for OPAM users.)
It's taken a bunch of experimentation, but I finally figured out how to have ocamlbuild pass the same flags to ocamlfind as ocsigen use in those makefiles. I'm also using js_of_ocaml installed with OPAM.
For my test case, I created a very small example with two files - main.ml and square.ml.
square.ml:
let square x = x * x
main.ml:
let () = (Js.Unsafe.coerce Dom_html.window)##square <- Js.wrap_callback Square.square
The command to build this successfully:
ocamlbuild -use-ocamlfind -pkgs js_of_ocaml,js_of_ocaml.syntax -syntax camlp4o main.byte
This produces identical JS output to my initial test case where the square function was in main.ml. The ocamlbuild log shows exactly what I expect (two calls to ocamldep, two to ocamlc -c, one to ocamlc -linkpkg).