I have a big project built by menhir and traditional makefile. First, I wanted to add a mechanism of error handling like this project to my project.
By following the dune of the sample project, I managed to generate .mly, .mli, .ml, .cmi and .cmo of unitActionsParser_e.mly by the following commands:
$ menhir --only-preprocess-u parser_e.mly > unitActionsParser_e.mly
$ menhir --table --external-tokens Parser_e unitActionsParser_e.mly
$ ocamlfind ocamlc -package menhirLib -c unitActionsParser_e.mli
And the incremental API and error handling did work.
Then, I wanted to add error recovery like this project to my project. Then, items state raised an error Error: Unbound value items in my project. Based on the manual and the dune, I guess I need to add --inspection somewhere.
I tried menhir --explain --inspection --table --dump --infer --external-tokens Parser_e unitActionsParser_e.mly, then camlfind ocamlc -package menhirLib -c unitActionsParser_e.mli raised an error Unbound type constructor Parser_e.terminal.
I also tried to directly work on parser_e.mly rather than using unitActionsParser_e by menhir --explain --inspection --table --dump --infer parser_e.mly, but it returned an error Unbound module Utility where Utility is a module in another folder needed by parser_e.mly. After I manually copied utility.cm* to the folder of parser_e.mly, it returned an error Unbound module Sedlexing (here is a fork where we can reproduce the error) (this is probably related to Interaction with build systems of the manual).
Does anyone know what are the correct commands and flags to generate a parser (either UnitActionsParser_e or Parser_e) enabling incremental API and inspection API of menhir?
(* link in discuss.ocaml.org: https://discuss.ocaml.org/t/generate-a-parser-enabling-incremental-api-and-inspection-api/9380 *)
This question is indeed related to the interaction of menhir and build systems. Precisely, the inspection API (--inspection) requires the type information of .mly (including its semantic actions) to be known. I chose to directly work on parse_e.mly rather than unitActionsParser_e.mly, and followed the approach of "Obtaining OCaml type information without calling the OCaml compiler":
menhir --explain --inspection --table --dump --infer-write-query mockfile.ml parser_e.mly to generate mockfile.ml
ocamlfind ocamlc -I lib -package sedlex -package menhirLib -i mockfile.ml > sigfile to generate sigfile. Note that -I lib refers to the directory of external modules, their .cm[io] files should be ready to use.
menhir --explain --inspection --table --dump --infer-read-reply sigfile parser_e.mly to generate especially parser_e.ml, parser_e.mli, .conflicts and automaton.
As a result, parser_e.ml contains more type information and the inspection API is in Parser_e.MenhirInterpreter.
Related
I'm using Ubuntu 18.04. I have OCaml 4.05 installed (via apt-get) as well as utop and Core (via opam). And this is the content of my ~/.ocamlinit:
(* Added by OPAM. *)
let () =
try Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH")
with Not_found -> ()
;;
#use "topfind";;
#thread;;
#camlp4o;;
#require "core.top";;
#require "core.syntax";;
Compiling OCaml codes which use Core works fine with corebuild. It doesn't work with plain ocamlc or ocamlopt though. They complain:
Error: Unbound module Core
And I found corebuild to be pretty picky. It doesn't like any existing non-OCaml codes in the same directory:
SANITIZE: a total of 12 files that should probably not be in your source tree
has been found. A script shell file "/home/anta40/Codes/_build/sanitize.sh"
is being created. Check this script and run it to remove unwanted files or
use other options (such as defining hygiene exceptions or using the
-no-hygiene option).
IMPORTANT: I cannot work with leftover compiled files.
ERROR: Leftover object files:
File hellod.o in . has suffix .o
File helloscheme_.o in . has suffix .o
File nqueens.o in . has suffix .o
File helloscheme.o in . has suffix .o
File HelloHS.o in . has suffix .o
File helloml.o in . has suffix .o
ERROR: Leftover OCaml compilation files:
File nqueens.cmo in . has suffix .cmo
File helloml.cmo in . has suffix .cmo
File helloml.cmi in . has suffix .cmi
File nqueens.cmi in . has suffix .cmi
File nqueens.cmx in . has suffix .cmx
File helloml.cmx in . has suffix .cmx
Exiting due to hygiene violations.
Compilation unsuccessful after building 0 targets (0 cached) in 00:00:00.
Using the -no-hygiene option, e.g corebuild sum.ml -no-hygiene doesn't produce any native executable. Is there any workaround?
`
The OPAM package manager can support multiple OCaml instances, where each groups an OCaml installation (ocaml, ocamlc, ocamlopt, etc.) with installed packages. Each instance is called a switch.
Type ocaml switch to see a list of instances. In terms of switches, the installation of OCaml using packages (apt-get) is called system.
It may be better to avoid mixing the system and OPAM installations. I suggest that you create a new switch, ensure that the OPAM settings are properly sourced, and install Core into it the new switch :
opam switch 4.06.1
eval $(opam config env)
opam install core
The automatic build tools assume that they control the entire build process and complain when they find other compilation results. Normally, running the suggested shell script and retrying side-steps the problem, even if only to uncover another one. Your second problem (with -no-hygeine) may be related to the installation issues.
Your installation is dated.
I imagine that you followed instructions in Real World OCaml but OCaml ecosystem has moved since the first edition of RWO. To get a modern installation you should follow the dev version of Real World OCaml https://dev.realworldocaml.org/install.html .
To answer your question, corebuild is a fine wrapper around ocamlbuild. To build an executable from a sum.ml with corebuild, you should use
corebuild sum.native
for native executable or
corebuild sum.byte
for bytecode compilation
Otherwise, you can invoke ocamlopt through ocamlfind:
ocamlfind ocamlopt -package core sum.ml
Finally, if you intend to build larger project, you ought to have a look to dune https://jbuilder.readthedocs.io/en/latest/overview.html .
I am building a new project using Eliom and having trouble setting up a compilation process for unit tests using OUnit.
I have two files:
Js_Client_Code.eliom - contains all of the client side code
Project.eliom - contains all of the server side code (including opening Js_Client_Code.eliom)
I have set up the files in this way so that I can run unit tests on Js_Client_Code.eliom without using ocsigenserver.
This is my current makefile for the tests:
test: prep unit_tests
prep:
eliomc -infer Js_Client_Code.eliom
js_of_eliom -linkall -a Js_Client_Code.eliom -o file_a.cma
eliomc -a -linkall Js_Client_Code.eliom -o file_b.cma
# Code is here to move the cma files back to the parent directory, since they are written to _client/ and _server/ by default
unit_tests:
ocamlfind ocamlc -thread -syntax camlp4o -package ounit,js_of_ocaml.syntax \
-linkpkg -g -o UnitTests file_a.cma file_b.cma unit_tests.ml
Running make test in the shell produces
File "unit_tests.ml", line 1:
Error: Error while linking file_a.cma(Js_Client_Code):
Reference to undefined global `Eliom_client'
Am I misunderstanding the Eliom/Js_of_ocaml compilation process, or just going about this the wrong way?
You're not linking the eliom libraries at all, so of course it's missing all the external modules.
Honestly, I don't think you'll manage to unit test modules that depends on eliom that way. It would probably be easier to unit test the non-eliom part indivdually, and do end-to-end browser-based tests (there are lot's of framework for that).
If you really want to try, there are explanations on eliom (or ocsigenserver)'s manual to link statically.
I am trying to generate documentation for a module of mine using ocamldoc. However, I use the Core library and ocamldoc complains about not finding it.
Error: Unbound module Core
I understand why thanks to this question, but it doesn't mention any solution for standard modules.
Any help?
ocamldoc needs to see the compiled interface for Core, i.e. the file core.cmi. This can be done through one of the following mechanisms:
Add the -I dir option to ocamldoc where dir is the directory where the core.cmi file lies. So for example ocamldoc -I $(opam config var core:lib) ... should do.
If you use the ocamlfind indirection, add -package core to the command line. E.g. ocamlfind ocamldoc -package core
I am trying to use ocamlfind to install a library. I am using OCamlMakeFile. Here is my Makefile:
OCAMLMAKEFILE = OCamlMakeFile
RESULT = owebl
SOURCES = src/utils.ml src/verb.ml src/request.ml src/template.ml src/response.ml src/rule.ml src/handler.ml src/server.ml
PACKS = unix str
all: native-code-library byte-code-library
install: libinstall
uninstall: libuninstall
include $(OCAMLMAKEFILE)
So basically the library is a collection of modules that I want to distribute. A basic usage of the library is (main.ml):
open Response
open Rule
open Verb
open Server
let handler =
Handler.create
(StaticRouteRule.create "/" [GET])
(FileResponse.create
~static_file:(FileResponse.StaticFile "/index.html")
())
let server = Server.create "0.0.0.0" 8080 [handler];;
server#serve
I compile the library just by running "make". It generates three files: "owebl.a, owebl.cma, owebl.cmxa". Then I install the library using ocamlfind:
ocamlfind install owebl META owebl.a owebl.cma owebl.cmxa
Oh, the META file is:
version = "0.1"
name = "OWebl"
description = "A Web Framework for OCaml"
archive(byte) = "owebl.cma"
archive(native) = "owebl.cmxa"
requires = "unix,str"
Everything works until I try to compile the above example that uses the library. I run:
ocamlbuild -use-ocamlfind -pkgs owebl main.native
And I get:
ocamlbuild -use-ocamlfind -pkgs owebl main.native
+ ocamlfind ocamlc -c -package owebl -o main.cmo main.ml
File "main.ml", line 1, characters 5-10:
Error: Unbound module Owebl
Command exited with code 2.
Hint: Recursive traversal of subdirectories was not enabled for this build,
as the working directory does not look like an ocamlbuild project (no
'_tags' or 'myocamlbuild.ml' file). If you have modules in subdirectories,
you should add the option "-r" or create an empty '_tags' file.
To enable recursive traversal for some subdirectories only, you can use the
following '_tags' file:
true: -traverse
<dir1> or <dir2>: traverse
Compilation unsuccessful after building 2 targets (1 cached) in 00:00:00.
make: *** [fileserver] Error 10
I tried adding open Owebl to the beginning of main.ml but I just got "unbound module Owebl" similarly. I'm pretty lost as to why these modules are all unbound. What am I missing?
You should use LIB_PACK_NAME variable if you want to pack your modules under umbrella namespace, like OWebl, otherwise they will be available just as it is, e.g. Response, Rule, etc. Also, you should specify the mli files as well as ml files in SOURCES variable. And finally, you shouldn't forget to install cmi files, as well as .a files. Installing mli files is also considered a good tradition, although is not strictly required. Also, consider using OCamlMakefile installation facilities instead of custom installation script.
I am no longer using OCamlMakefile therefore am not sure, but assuming OCamlMakefile compiles things with -for-pack OWebl option and properly builds a packaged module owebl.cmo, you also need to install owebl.cmi.
OCaml compiler seeks cmi files to check the existence of modules and to get their type information. If not installed, the compiler cannot find it. cma and cmxa files are collections of objects and do not provide type information.
In the same vein of using:
ocamlc -i foo.ml
to generate the default signature for foo.ml is there a way to generate signatures from compiled files (*.cmo) or archives (*.cma)?
My use case is that I have an archive abcd.cma I want to link with, containing numerous modules (say, modules a, b, c and d) and I don't want to bother with the multiple *.mli and *.cmi my Makefile would need to handle to compile and link the user-side code (that uses the library). E.g. say I have file uses_a.ml that uses only the a module found in the abcd.cma archive. My understanding is that to link with the abcd.cma module I would have to go through the following motions:
ocamlc -i a.ml > a.mli
ocamlc -c a.mli
ocamlc -c uses_a.ml
ocamlc abcd.cma uses_a.cmo
Which seems too convoluted or impossible if I don't have access to the sources or the signature. Given that I provide the entire archive to the compiler at the last command it is not clear to me why I have to go through the ritual of compiling (or generating - if I have access to the sources) the specific signature file for the module I am using. The last command could have been interpreted by the tool as an invitation to use the "default" signature of any module present in the archive that subsequent modules on the line use. BTW I don't want to use automatic Makefile generation tools at this point.
If you have to compile a.ml and a.mli, there is no point having a library.
A library is normally composed of a abcd.cma file (or both abcd.a and abcd.cmxa in native code) and the set of interfaces (.cmi files) of the modules that are exported from the library. So, normally, in your case, the file a.cmi should be provided altogether with the library.
In such a case, you just need to do:
ocamlc -I path/to/directory/containing_a.cmi -c uses_a.ml
ocamlc -o program.opt abcd.cma uses_a.cmo