How to use reasonml rtop with src files - ocaml

How do I allow rtop to discover my src file directory?
I found an option -I and hoped that rtop -I src would load my src files in rtop but it still isn't able to find them.
eg.
src/lib.re:
let foo = 1;
Run command:
rtop -I src
Reason # open Lib;
Error: Unbound module Lib

open is a language feature that doesn't know anything about the file system. You'll have to use a special directive instead to load the module from a file.
utop/rtop mostly uses the same directives as the ocaml toplevel, which are documented in the OCaml manual, here.
If the module has been compiled, you can load the .cmo or .cma using the #load directive:
#load "filename";;
If that module depends on other modules, you can use #load_rec instead to load them recursively.
If your code has not been compiled, and since you open it immediately, you can also use the #use directive:
#use "filename";;
Or if you want to load it as if was a top-level module, use #mod_use instead.

Related

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.

Using ocamlmktop with ocamlbuild

I have a project that builds successfully using ocamlbuild. However, I would also like an easy way to interact with the project's individual functions from different modules via the toplevel but my attempts at using ocamlmktop haven't worked out as I'd like. I've found that unless I manually put the .cmi files in the active directory, I get an "Unbound module" error. The command I'm currently using to build is:
ocamlfind ocamlmktop -I _build -o my_ocaml -linkpkg -package str module1.cmo module2.cmo
Is there a better, less hacky way to get the toplevel to work in this project structure without moving cmi files out of the _build directory?
Edit: I've figured out that I can get it to load the types and modules if I run the toplevel as
./my_ocaml -I _build
But this still seems hacky. Is there a way to bake the search path or cmi files in perhaps?
Edit 2: I think the solution to my problem may actually be not to compile a custom toplevel at all given this restriction about interface files. I have instead added load directives to my .ocamlinit to use the modules. If anybody has better ideas to solve this, I'd greatly appreciate it.
You can build a toplevel by listing the module names you want in a my_ocaml.mltop file:
Module1
Module2
subdir/Module3
Then building the target my_ocaml.top will call ocamlmktop in the expected way, and you can run the resulting my_ocaml.top toplevel.
This does not change the way that you need to add _build to the include path for the type-checker to be able to find the .cmi files. You can do this when you invoke the toplevel by passing the command-line arguments -I _build, or from the toplevel with #dir "_build";; -- the last command can also be put in your .ocamlinit if you prefer.

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

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.

about basic file organization

in file testmodule.ml
module TestModule =
struct
type my_type = MyType1 | MyType2
end
How can I use TestModule in top-level?
after "ocamlc -c testmodule.ml" (this generated testmodule.cmo/cmi)
I tried "open TestModule", but error "unbound module TestModule" occured.
Objective Caml version 3.10.0
# open TestModule;;
Unbound module TestModule
then, I tried making top-level with that module. but...
indi#www:~/std/toq$ ocamlmktop -o mytop testmodule.ml
indi#www:~/std/toq$ ./mytop
Objective Caml version 3.10.0
# TestModule.MyType1;;
Unbound constructor TestModule.MyType1
# open TestModule;;
Unbound module TestModule
What can I do for using my TestModule???
The directives you can use in the toplevel to that effect are listed in the manual.
You can try #use "testmodule.ml";;, or, alternatively #load "testmodule.cmo";; after having compiled your module.
As huitseeker mentioned, you can use #use "testmodule.ml";;. However, this will make the module Testmodule avialable, and your TestModule module is actually Testmodule.TestModule. .cmo files (generated from .ml files) define a module whose name is that of the CMO with the first letter capitalized. Therefore, I would omit the module TestModule ... part of your code, and simply put your code in a file called testModule.ml. You can then compile it and use #use "testModule.ml";; to access the module.
Tu summarize: a few minor details all conspired together against you :-)
First, as mentioned previously, you need to load the code into the toplevel with either #use "testmodule.ml";; for source files or #load "testmodule.cmo";; for compiled files, or to use ocamlmktop. This explains why your first attempt did not work: you did not load the code.
Second, you defined module TestModule in a file called testmodule.ml. Keep in mind that the file defines its own module based on its name. So, in order to access your module, you need to write Testmodule.TestModule. This explains why your second attempt did not work: the code was loaded but had an unexpected name.
You might wish to remove the TestModule definition and rename the file to testModule.ml (or the perhaps more idiomatic test_module.ml).