Generate dump/explain files of Menhir when using ocamlbuild - ocaml

I discovered that Menhir provides --dump and --explain options and it helps debugging a lot. But how can I enable these options under ocamlbuild so that Menhir always generates dump files at compile time?
I tried to write myocamlbuild file handling custom tag menhir_dump like the below:
... snip ...
(* OASIS_STOP *)
Ocamlbuild_plugin.dispatch (
MyOCamlbuildBase.dispatch_combine [
(function
| After_rules ->
flag ["menhir_dump"] (S [A "--dump"; A "--explain"])
| _ -> ()
);
dispatch_default
]
)
But when it compiles, the options are inserted into sub-command and the compilation fails during ocamlc stage.
menhir --dump --explain --raw-depend --ocamldep 'ocamlfind ocamldep -modules' src/parser.mly > src/parser.mly.depends
menhir --ocamlc 'ocamlfind ocamlc -g -annot -bin-annot --dump --explain -I src -package cmdliner -package menhirLib -I src' --dump --explain --infer src/parser.mly
+ menhir --ocamlc 'ocamlfind ocamlc -g -annot -bin-annot --dump --explain -I src -package cmdliner -package menhirLib -I src' --dump --explain --infer src/parser.mly
^^^^^^^^^^^^^^^^
ocamlc: unknown option '--dump'.
...snip...
Any suggestions?

I answer it myself.
There is, of course, a built-in ocamlbuild option for this. Just put explain in _tags like the below.
true: use_menhir, explain
You may lookup built-in options using ocamlbuild -documentation.

Related

How to compile a file that uses the JsooTop module?

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.

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.

Ocamlbuild doesn't take in account the included folders

I am trying to use ocamlbuild to build my project. It needs to take into account an external library (also compiled with ocamlbuild) that contains in the folder myfolder/ the following files (myfolder is a symlink to the good library that I create in the file myocamlbuild.ml):
$ ls _build/myfolder/
PhTools.cmi PhTools.ml PhTools.mli
PhTools.cmo PhTools.ml.depends PhTools.mli.depends
To compile my library I run the following command:
ocamlbuild -use-ocamlfind -plugin-tags "package(eliom.ocamlbuild),package(containers),package(fileutils)" -Is "myfolder" -mods "myfolder/PhTools.cmo" _server/./TestHelloServices.cmo
When I run it I have the error:
[...]
ocamlfind ocamlc -I '' -I _server -I _type -i -thread -package eliom.server -package eliom.syntax.predef -package eliom.syntax.type -syntax camlp4o _type/TestHelloServices.ml > _type/TestHelloServices.inferred.mli
+ ocamlfind ocamlc -I '' -I _server -I _type -i -thread -package eliom.server -package eliom.syntax.predef -package eliom.syntax.type -syntax camlp4o _type/TestHelloServices.ml > _type/TestHelloServices.inferred.mli
File "TestHelloServices.eliom", line 6, characters 10-17:
Error: Unbound module PhTools
Command exited with code 2.
As you can see the option -I myproject hasn't been given to the command ocamlfind ocamlc -i .... You can note that if I add by hand ocamlfind ocamlc -i -I 'myproject' this step works. I tried lot's of differents things to solve my problem : using -cflags '-I,myproject' -lflags '-I,myproject', putting in _tags the line:
myproject: include
but I always have this error.
I don't know if it's a relevant information but I use a slightly modified version of the ocsigen myocamlbuild.ml file:
let client_dir = "_client"
let server_dir = "_server"
let type_dir = "_type"
module M = Ocamlbuild_eliom.Make(struct
let client_dir = client_dir
let server_dir = server_dir
let type_dir = type_dir
end)
open Ocamlbuild_plugin;;
let () =
dispatch begin function
| Before_options ->
M.dispatcher Before_options;
(* Link root project *)
(try
Unix.symlink "../../../../../myfolder/" "_build/myfolder"
with Unix.Unix_error (Unix.EEXIST, _, _)-> ());
| hook -> M.dispatcher hook
end;
Thank you in advance,
TobiasBora.
I guess ocamlbuild will not follow "external" (out of project tree) links.
Maybe hardlink will work, but better yet install the library as the normal ocamlfind package.

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).

ocaml batteries compiling : Unbound module Toploop

**Build mode: shared
ocamlbuild -no-links syntax.otarget byte.otarget src/batteries_help.cmo META shared.otarget
Finished, 0 targets (0 cached) in 00:00:00.
+ ocamlfind ocamlc -c -g -annot -warn-error A -package camomile,num,str -package camlp4.lib -pp camlp4of -pp camlp4of -I libs/estring -I benchsuite -I src -I testsuite -I build -I qtest -I libs -I src/syntax/pa_comprehension -I src/syntax/pa_strings -o libs/estring/pa_estring_top.cmo
libs/estring/pa_estring_top.ml
File "libs/estring/pa_estring_top.ml", line 18, characters 15-44:
Error: Unbound module Toploop
Command exited with code 2.**
Compilation unsuccessful after building 6 targets (5 cached) in 00:00:00.**
I have found toploop.cmi in path:
cd OCaml/lib/ocaml/compiler-libs/
ls topl*
toploop.cmi
and as you see,
export PATH=/home/xxx/OCaml/lib/ocaml/compiler-libs/:$PATH
I have made /home/xxx/... as my system path. But it still did not work. What I should do to include the module toploop?
You appear to be compiling Batteries (which version?) with OCaml 4.00, which introduced the new compiler-libs directory (but some distributions had one before so that may be off). toploop used to be at the root of the OCaml stdlib's directory, but you should now add a -I +compiler-libs option somewhere, or use the corresponding ocamlfind packaging (-package compiler-libs.toplevel).