(Ocaml) unbound module error on visual code - ocaml

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.

Related

Unbound Module (Personal Files)

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.

Loading OCaml modules not in the current directory

I'm writing a large OCaml project. I wrote a file foo.ml, which works perfectly. In a subdirectory of foo.ml's directory, there is a file bar.ml.
bar.ml references code in foo.ml, so its opening line is:
open Foo
This gives me an error at compile time:
Unbound module Foo.
What can I do to fix this without changing the location of foo.ml?
The easy path is to use one of OCaml build system like ocamlbuild or oasis. Another option would be jbuilder but jbuilder is quite opiniated about file organization and does not allow for the kind of subdirectory structure that you are asking for.
The more explicit path comes with a warning: OCaml build process is complicated with many moving parts that can be hard to deal with.
After this customary warning, when looking for modules, OCaml compiler first looks for module in the current compilation environment, then looks for compiled interface ".cmi" files in the directories specified by the "-I" option flags (plus the current directory and the standard library directory).
Thus in order to compile your bar.ml file, you will need to add the parent directory in the list of included directories with the -I .. option.
After all this, you will discover that during the linking phase, all object files (i.e. .cmo or .cmx) need to be listed in a topological order compatible with the dependency graph of your project.
Consequently, let me repeat my advice: use a proper build system.

load|use|require a library object file within an Ocaml source file

The Ocaml manual contains an exercise (here) in which library object files are loaded in the toplevel loop (the ocaml interactive interpreter) in the following way:
#load "dynlink.cma";;
#load "camlp4o.cma";;
I'm trying to replicate the subsequent code in a compilable source file, and the code requires the above library object files. Can I load these files with a line of code within the source file and compile it with ocamlc? I've tried "#load", "load", "#use", "use", "#require", "require", and all these proceded by "#directory" and "directory". I know that you can include modules with "include ;;", but this shouldn't work either, because they're just library files, not modules. I've tried to find a way to do this in the manual, but to no avail.
Do I need to reference the files in the compilation command? If so, how do I do this?
Directives starting with a # character are used only in the toplevel and are not strictly part of the OCaml language. In a file that you want to compile, you don't use # directives. See the OCaml manual Chapter 9. The #load directives are for loading a library. When compiling a file, you have to tell the compiler to use the library (on the command line, not in the file). It's good to learn the compiler commands directly at first, but eventually you should use ocamlfind and oasis, which make compilation much easier.
I'm assuming your source is written using extensions implemented by camlp4o. To compile your source, you can say:
ocamlc -pp camlp4o -o myfile myfile.ml
I believe the complexities of the #load command are required only when you want to use the extensions in the toplevel (the interpreter).

node.js Internals: How can I find out where `process.binding('eval')` gets defined?

How can I find out where in the C++ source code of node.js the JavaScript object gets defined which I can access through process.binding('eval')? - I already found out that it's in /src/node_script.cc in this special case, but: How can I know where I can find that module just when I just take a look on the /src/ directory overview? I don't want to step through all the files in /src/ in order to look for a module.
Where can I find some deep going information about the internals of process.binding()s?
Thanks.
I was looking for the same myself today. I cannot guarantee that there isn't more to it, but this is what I discovered.
src/node_extensions.h contains a list of built-in modules, defined like:
ITEM(node_module_name)
where module_name is the name of the module (obviously)
You can find out which file defines that module by searching for which file has a line that starts with
NODE_MODULE(node_module_name,
So, to find the file that defines the 'evals' module for process.bindings:
$ grep "NODE_MODULE(node_evals" src/*.cc
src/node_script.cc:NODE_MODULE(node_evals, node::InitEvals)

2 ocaml modules with same (file)name

What I want is to have the following source tree layout:
src/
a.ml
b.ml
...
tests/
a.ml
b.ml
...
Is it possible to distinct these modules and access
src/a.ml module as A and tests/a.ml module as something like Tests.A ?
Actually, there also is a problem with ocamlfind (UPD: omake) it thinks that tests/a.ml depends on itself rather than on src/a.ml
Of course, I can just rename the tests as, like, tests/aTest.ml, but I would like to avoid having to do it. And I just don't believe that it's impossible to have any similarly-named files in the whole source tree (regarding distinction purposes -- isn't it what folders and the whole hierarchical file systems thing are for?)
Thank you very much!
-pack option can be used to group the set of compiled objects under the single module name.
Actually, there also is a problem with
ocamlfind: it thinks that tests/a.ml
depends on itself rather than on
src/a.ml
ocamlfind doesn't deal with deps between source files. ocaml compiler itself will not be able to resolve module names in such setup.
And yes, it is better to avoid similarily named files in source tree :)