OCamlfind local library unbound module - ocaml

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.

Related

Is it possible to compile OCaml codes using Core without corebuild?

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 .

Use ocamlfind with ocaml interpreter, without compiling

I have a file main.ml that uses some package that makes the command ocaml main.ml fail and report this error:
Error: Unbound module X
And the only solution I've found so far is to run:
ocamlbuild main.native -use-ocamlfind -package X
./main.native
But this compiles the file. Is there a way to just run the regular ocaml interpreter (ocaml main.ml) with some additional flags to make it find the package?
The easiest way is probably to use topfind and add #require "core" at the top of your file. If you want to avoid adding toplevel directives in your file, you can use ocamlfind query -i-format -r to compute the required include directories:
ocaml $(ocamlfind query -i-format -r core) main.ml
You can put at the beginning of your file some top-level directives which find and load needed modules. For example, when I want to use Core library in my script I insert:
#use "topfind";;
#thread;;
#require "core";;
open Core.Std
(* Code of my script *)
To use topfind package ocamlfind has to be installed (opam install ocamlfind)
You can also query the path of your package to ocamlfind :
ocamlfind query package_X
That will return the path of your package : /path_to/packageX
And then :
ocaml main.ml -I /path_to/packageX

ocamlbuild: build plugin with options

I'm trying to write an ocamlbuild plugin (myocamlbuild.ml) that will use definitions from another file. I have a lot of definitions that I'd like to be used across several build plugins and I wanted put them in their own file. I tried running ocamlbuild twice, once with -no-plugin just to build the plugin, e.g.
ocamlbuild -no-plugin myocamlbuild.cmo
and then again afterwards
ocamlbuild actual-targets.otarget
but when I run the second one it tries to rebuild the plugin and complains that it can't find the included library (even though it exists in the _build directory). So, is there any way that I can convince ocamlbuild to include '-I _build _build/coq_paths.cmx' on the command line? From 'ocamlbuild -help' it looks like there is a '-plugin-option' flag, but I can't find any way to use it.
Thanks.
Since 4.01, ocamlbuild supports a new (experimental) option -plugin-tag that allows to specify (built-in) ocamlbuild tags to use when compiling myocamlbuild.ml. If you package "coq-paths" using findlib, you can then use
ocamlbuild -use-ocamlfind -plugin-tag "package(coq-path)" ...

ocamlmktop with oasis

I am having trouble adding adding a library to ocamlmktop.
I have a directory com, with an object file com/com.cma.
If I run ocamlmktop com.cma -o top within the com directory, then the resulting executable top seems to have the library; i.e, I can enter "Com.foo;;" and it will give the type signature of foo in the module Com.
However, if I run ocamlmktop com/com.cma -o top within the directory above com, then the resulting executable does not seem to have the library; i.e, it responds to "Com.foo;;" with "Error: Unbound module Com".
Is there a way to include libraries from different folders, or do I need to put all the .cma files in the same folder?
Also, I'm using the OASIS build system; can I inform OASIS that I want a toplevel with these libraries?
Edit:
I've found a partial solution: ocamlc -pack a/a.cmo b/b.cmo -o everything.cmo, and then ocamlmktop everything.cmo -o top; however, this requires duplicating all the libraries and forces them to be submodules of a single supermodule.
The reason that you cannot use toplevel from the directory above is that toplevels do not include interface files (.cmi) and the toplevel needs to find them on disk when the user accesses some module. So, either load toplevel with -I com switch or after loading issue #directory "com";;.
NB OASIS should support building toplevels natively in the next release (0.4.0).

Using "ocamlfind" to make the OCaml compiler and toplevel find (project specific) libraries

I'm trying to use ocamlfind with both the OCaml compiler and toplevel. From what I understood, I need to place the required libraries in the _tags file at the root of my project, so that the ocamlfind tool will take care of loading them - allowing me to open them in my modules like so :
open Sdl
open Sdlvideo
open Str
Currently, my _tags file looks like this :
<*>: pkg_sdl,pkg_str
I can apparently launch the ocamlfind command with the ocamlc or ocamlopt argument, provided I wan't to compile my project, but I did not see an option to launch the toplevel in the same manner. Is there any way to do this (something like "ocamlfind ocaml")?
I also don't know how to place my project specific modules in the _tags file : imagine I have a module name Land. I am currently using the #use "land.ml" directive to open the file and load the module, but it has been suggested that this is not good practice. What syntax should I use in _tags to specify it should be loaded by ocamlfind (considering land.ml is not in the ocamlfind search path) ?
Thank you,
Charlie P.
Edit : According to the first answer of this post, the _tags file is not to be used with ocamlfind. The questions above still stand, there is just a new one to the list : what is the correct way to specify the libraries to ocamlfind ?
try this:
$ cat >> .ocamlinit
#use "topfind";;
#require "sdl";;
#require "sdlvideo";;
open Sdl
open Sdlvideo;;
open Str;;
.ocamlinit is sourced from the current directory, falling back to /home/user/.ocamlinit. you can explicitly override it via ocaml -init <filename>
One should distinguish ocamlfind packages, module names and file names. Source code references only module names. Modules are provided by .cma .cmo .cmx (and .cmi) files. Ocamlfind packages are named collections of such files (binaries built from some ocaml library sources). Ocamlfind is not strictly necessary to build a project - just specify the paths to all used libraries via -I. But if the project is distributed in source form - another people will have troubles building it cause used libraries are placed in different places. Then one seeks the way to specify the names of used "third party code pieces" and some external tool to resolve those names to actual paths. This tool is ocamlfind.
First find the ocamlfind package that provides the modules you need (in this case Sdl and Sdlvideo - just run ocamlfind list, most probably the package is named sdl.
Compile with ocamlfind ocamlc -package <package name> -linkpkg source.ml -o program
Alternatively use ocamlfind to extract the path to the .cma file (and others) provided by the package (ocamlfind query <package name>) and use this path with your build tool (plain Makefile, ocamlbuild, etc).
Moreover ocamlfind (is intended to) take away the burden of remembering how the actual .cma files are named and what matching compiler options are required and in what order the packages are depending on each other. One just needs to specify the package name.
Keep in mind that there is no one-to-one strict formal relationship between library name (purely human-targeted name e.g. ocaml-extlib), module names (ExtLib, Enum, IO, etc), file names (extLib.cma) and ocamlfind package name (extlib), though for convenience package maintainers and library authors usually choose guessable names :)
The _tags file is not for ocamlfind, but for ocamlbuild.
Exemple :
ocamlbuild land.native