Unbound Module (Personal Files) - ocaml

I have two .ml files, type.ml and main.ml, in the same directory.
I am following this official link: https://ocaml.org/docs/modules
File main.ml:
open Type
let () = print_endline "Hello World!"
I compile with this line, accordingly to the tutorial:
ocamlopt -o main main.ml type.ml
However, I have this error:
Error: Unbound module Type

The source files need to be ordered with the dependencies coming before the dependent. That is, it should be:
ocamlopt -o main type.ml main.ml
This is somewhat vaguely explained in the manual:
The order in which .cmx and .ml arguments are presented on the command line is relevant: compilation units are initialized in that order at run-time, and it is a link-time error to use a component of a unit before having initialized it. Hence, a given x.cmx file must come before all .cmx files that refer to the unit x.
Also, if you're doing anything more significant I would recommend using a build system like dune to avoid having to mess with details like this.

Related

(Ocaml) unbound module error on visual code

I have just started to learn Ocaml.
I'm using visual code as my IDE on Ubuntu,
and I have OCaml extension and merlin installed.
and I have the following problem -
my workspace folder contains only 2 files:
a.ml and b.ml.
In the file a.ml I have defined a module named "COOL", and in the file b.ml I wrote:
~ b.ml ~
open COOL;;
I get an error that says "Unbound module COOL merlin"
Is there any way to make it see the module on file a.ml?
I tried searching for solution, I saw something with makefile and .merlin and B build
but I didn't understand it, I don't have anything but the 2 files I mentioned.
I would be happy if someone can tell me what exactly should be done in order for this little example to work.
tl; dr: do ocamlc -c a.ml (or whatever your compilation command is) in order to generate the a.cmi file that merlin will use to get the list of symbols defined in module A.
Apart the fact that in b.ml your module is indeed named A.COOL (unless you open A before open COOL) as mentioned by glennsl, the point is that merlin is, as far as I know, only watching the current file being edited, i.e. b.ml in your case. In order to have access to external symbols, you thus need to have compiled the other files (or at least their corresponding .mli if they exist), in order to have the relevant .cmi files available to merlin.
This is implicit in the paragraph of the documentation describing build paths, which says "[merlin] needs to know where to find the cmi files of the other modules of your project", i.e. those files need to exist in the first place.

Compiling and Running Ocaml Script from the Terminal

I have files called assert.ml, assert.mli, test.ml and test.mli stored in a folder. assert is I guess you'd call it a library file--it's something I downloaded but didn't write myself. test.ml is a file containing the script
;; open Assert
;; print_endline "test"
In the terminal I navigate to the containing folder and run
$ ocamlc -c assert.mli test.mli
$ ocaml assert.ml test.ml
Nothing happens as a result. However, if I remove the ;; open Assert line from the script and run
$ ocaml test.ml
then it prints.
As a note, I've had some people tell me not to write the open command as ;; open Assert but the advice seems entirely stylistic. I have to write it this way for the class I'm taking.
If anyone can explain to me how I ought to be compiling and running differently I'd appreciate it. I tried following some other guides' advice in using ocamlopt instead but when I ran it, no executable file was produced as a result.
The ocaml command is the REPL for OCaml. The command line looks like this:
ocaml [ object-files ] [ script-file ]
An object file is a compiled (bytecode) module, which is produced by the ocamlc command. These files end with .cmo. A script file is a file of OCaml source code, which ends with .ml.
Note that only one script file is allowed.
The command you say you're using has two script files and no object files. So, it's not surprising that it doesn't work. In my experiments, what ocaml does is run just the first of the two script files. I believe this explains what you see. One of your files produces output, and it will be run if you give it first. The other produces no output, so there is no output when that file is given first.
What you should probably be doing is producing a .cmo file for the Assert module.
That would look like this:
$ ocamlc -c assert.mli assert.ml test.mli
Then you should run ocaml with one object file and one script file, like this:
$ ocaml assert.cmo test.ml

Ocamldoc and open modules

I'm trying to document a small project of mine using ocamldoc.
I have one main .ml file which opens two others .ml files.
$ ocamldoc -html included1.ml included2.ml
Works just fine, but when I add the including file, like
$ ocamldoc -html included1.ml included2.ml including.ml
I get this:
File "including.ml", line 5, characters 5-16:
Error: Unbound module Included1
1 error(s) encountered
I see from the ocamldoc documentation that opening modules is perfectly fine, until no conflict arises.
How should I proceed?
It's fine for a module to use other modules however it needs to be able to see the compiled interfaces for those. So in your case you first need to compile the .ml files to generate .cmi files. Then you need to indicate to ocamldoc where these files are. So something like this should do:
ocamlc -c included1.ml
ocamlc -c included2.ml
ocamlc -c -I . including.ml
ocamldoc -html -I . included1.ml included2.ml including.ml
Note that in general it's a good (essential) practice to create .mli files for each of your modules an document and ocamldoc these rather than the .ml files.

Creating an OCaml library

I am trying to create a library that I can use in other OCaml projects, and I'm totally lost.
I'm currently using ocamlbuild which is great for spitting out executables, but I don't know how to get a library out of it.
I've discovered the -a option in ocamlopt and ocamlc but I'm not really sure how to use it. The documentation I've found (for example, here), seems to assume some preexisting knowledge. I don't even know what a .a file is. After I run that, which of the outputted files do I need to build a project that depends on this library? Do I need the mli files so that the application knows the signatures of the library code, or is that included in the output somehow? Also, it would be nice to be able to package all the files together, something similar to a .jar file for Java.
In any case, I would love for ocamlbuild to do all of this for me, since if I have to invoke ocamlopt -a I will have to either manually specify dependencies or hack a script around ocamldep -- something that ocamlbuild was supposed to fix. However, I don't know how to tell it to build a library.
I'm willing to use oasis or OPAM or something if it's necessary, but I would like to learn how to do this using just the basic tools first.
OCamlbuild has some built-in functionality for building libraries, so you can get started with just ocamlbuild foo.cma foo.cmxa (assuming foo.ml is your entry point). This will invoke ocamlopt -a and ocamlc -a for you, handling all the dependency plumbing and leaving the generated files inside _build.
That should be enough to let you compile a library and link it from another program. Since this is just a test you can simply point at the aforementioned _build with -I when compiling the program that uses the library. For real use a library should be packaged - when you get to that point you'll want to look into ocamlfind, oasis, etc.
Have a look at the ocaml.org tutorial on compiling OCaml projects. Additionally the official manual for the bytecode and native code compilers contains useful detail on producing and using the various types of files.
The documentation for ocamlbuild archives seems to cover this pretty well.
In any case, here's one way to do ocaml libraries. Let's say you have a directory called foo containing your .ml, .mli, and .mllib files. Let's say it contained bar.ml, bar.mli, baz.ml, and baz.mli. To distribute all this as one library, you'd also have a foo.mllib in that directory, whose contents are
Bar
Baz
Then to compile, do
$ ocamlbuild -use-ocamlfind foo.cma foo.cmxa
Here is an example.
Then to use your library foo, let's say you had a sibling directory called main, and main contains main.ml, _tags, myocamlbuild.ml.
myocamlbuild.ml should have the following contents:
open Ocamlbuild_plugin
open Command
let () =
dispatch (
function
| After_rules ->
ocaml_lib
~extern:true
~dir:"/path/to/foo/_build"
"foo"
| _ -> ()
)
_tags should have the following contents:
<main.{ml,native,byte}>: use_foo
Compile main.ml with
$ ocamlbuild -use-ocamlfind main.byte main.native
run with
$ ./main.byte
$ ./main.native
More information here as well: https://ocaml.org/learn/tutorials/ocamlbuild/Using_an_external_library.html

examine library (.cma) signature from console

Say I have an OCaml library file foo.cma. Is there a command line tool to print the signature of the functions and other types defined there ? The ocamlbrowser utility seems to be windows-based (complains about the $DISPLAY environment variable). The use case is that I am doing a:
ocamlc -c foo.cma main.ml
and get:
File "main.ml", line 13, characters 33-47:
Error: Unbound value ListUtil.split
ListUtil.split ought to reside in foo.cma but I don't know a console-based tool to verify it.
On Debian/Ubuntu, you have "ocamlobjinfo":
ocamlobjinfo stdlib.cma
will display all the unit names included in stdlib.cma. Then, you can create a short file:
include SomeModule
and compile it with -i to see what is defined in module SomeModule.
In the toplevel, I just load the cma file:
#load "foo.cma";;
Then I re-defined a module just to see the signature:
module Chunk = Foo;;
In order to compile the code referencing ListUtil.split the compiler needs to find the corresponding listUtil.cmi file. In order to link that code compiler will need the cma (or cmo) file containing the implementation. See http://mirror.ocamlcore.org/caml.inria.fr/pub/ml-archives/caml-list/2008/09/2bc9b38171177af5dc0d832a365d290d.en.html for some explanation.