how to chose between two implementation code in OCaml - ocaml

I have uploaded the very small exemple project on a github repository
I have a school project. The specifications say that we can enable or disable a component.
I came from the c world in which we can compile c to object and chose the object to link. I try this in OCaml.
I have two source file with the same function but their effect is different.
I have two folders called "on" with implementation and "off" folder with an empty body
For the test, I have a simple a.ml and a.mli file that only print hello world and b.mli b.ml that call the module a. (so I have on/a.ml and off/a.ml)
I compile the on version and the off with this command:
ocamlc -c -I on on/a.mli on/a.ml -o on/a.cmo
then I try to link the C-way
ocamlc on/a.cmo b.ml -o on_b.exe
but I get the error
File "b.ml", line 1, characters 9-15:
Error: Unbound module A
I have then read I should specify the folder to search in with -I.
ocamlc -I on -I off on/a.cmo b.ml -o on_b.exe
I was happy because of that work for the on version
but it will not work for the off version
ocamlc -I on -I off off/a.cmo b.ml -o off_b.exe
I get the error
Error: Files b.cmo and off/a.cmo
make inconsistent assumptions over interface A
I have inspected with ocamlobjinfo it seems to build B its searches for the first module called A
In this example, I have only A and B but in future, I will build with some version on and some off... but don't do it manually
A solution found but no really efficient is to clean all .cmo and .cmi files ...
thanks for your reading and your time
EDIT:
I have also test with -open but it seems to work only for standards modules.

As you can see, compiling your .mli files produces a .cmi file. This is the file that you indicate is there by using the -I dir option.
So, if I understand you correctly, you have a a.mli in both your on and your off directory.
Now, when you refer to the module A in your code, the compiler looks for it in the current directory, then in the linked directories in the order they are given. When you compile "on", the right .cmi is found (because -I on comes before -I off in your command line). In the case of "off", the "on" cmi is found, and the compiler sees that it doesn't correspond to the right cmo.
Your two compiling lines should be:
ocamlc -I on on/a.cmo b.ml -o on_b.exe
ocamlc -I off off/a.cmo b.ml -o off_b.exe

Related

What does the "#" symbol mean in a makefile when after an -I flag such as -I #mathinc#?

I'm trying to understand the following line in a Makefile.in file:
CXXFLAGS += -O3 -DNDEBUG -std=c++11 -Wno-deprecated-declarations -Isrc -I #mathinc#
I know the -I flag adds a directory to the list of places where the compiler will search for included files but what does #mathinc# mean?
Note that the file is called Makefile.in -- this signifies that it is input to another file (or transformation).
In short, configure will run and determine, say, where the relevant include files are for #mathinc -- likely some math headers. After you run configure it will produce Makefile (no trailing .in) based on what it finds. Do inspect that file.
configure scripts are created in a system called autoconf which, like all build systems, has its fans and its haters. There are some decent tutorials as for example this one.

how to run bonmin from a cpp program

I’ve already downloaded Bonmin-1.8.8 and compiled it. The usersmanual said that there is a cpp example in the /bonmin/examples/cppexample.I added the bin and lib to my Path but when I coded
g++ mybonmin.cpp -o mybonmin
It shows that cannot find the headfile. I want to know how can I run Bonmin with the cpp program.
Try passing the flag to the headers:
g++ mybonmin.cpp -I/home/mybonmin -o mybonmin
here more info about it:
-I [/path/to/header-files]

How to separate binary code from source in ocaml?

I have my source next to a build directory
ocamlc -c file1.ml
ocamlc -c file2.ml
…
ocamlc -o main.ml ….cmo
I have the source with the file generated by the compilation.
I would like an option of ocamlc that enable me to have this file in the build directory.
I know i can do ocamlc -o build/main.ml .....cmo but i would like to have to .cmo in the build directory too
Thank you for your help
The answer of your main question is very simple:
in order to put the main binary of your OCaml application in the build folder, you just need to run:
ocamlc -o build/main.exe main.ml ….cmo
Indeed as indicated in the documentation (man ocamlc):
-o exec-file
Specify the name of the output file produced by the linker. The
default output name is a.out, in keeping with the Unix tradition. […]
However, doing all the build steps by hand in the way you are suggesting in your question may not be very effective (in particular, all .cmo files will stay along with the sources in the same folder).
To avoid this and facilitate the build of your OCaml project, I suggest using a build management tool for OCaml, for example one of the four tools mentioned in the end of the tutorial Compiling OCaml Projects:
ocamlbuild
GNU make
OMake
Oasis
(ocamlbuild is probably the easiest tool to use among the four.)
But you may also consider using Dune (formerly known as JBuilder), which is the build system used by a majority of packages in opam.

C++ source compilation using MATLAB Engine and g++

It would be helpful if you could provide some guidance on how to compile c++ source code files in an Ubuntu environment, using the MATLAB Engine with g++.
I assume that you want to know the procedure for compiling the c++ code (which calls MATLAB engine) using g++ from Linux Terminal. To do so, follow the steps below:
Include following paths in PATH variable:
a) Location of MATLAB i.e. $matlabroot/bin
b) $matlabroot/sys/os
You can do this by using the command
'setenv PATH $matlabroot/bin:$matlabroot/sys/os:$PATH ' .
In the command prompt, navigate to the directory where the cpp code is located using cd command. For instance, if you are compiling engdemo.cpp, you need to navigate to $matlabroot/extern/examples/eng_mat/engdemo.cpp
You need to call the compiler with required include files and libraries. For this you can use -I and -L switches for that. Note that the order is important. So you need to use the command as below:
g++ engdemo.cpp -I "$matlabroot/extern/include" -L "$matlabroot/bin/glnxa64" -leng -lmat -lmex -lut -o engdemo.o
The above command will generate an object file engdemo.o. To execute this, use the command ./engdemo.o
You can refer to the document at http://www.umiacs.umd.edu/~jsp/Downloads/MatlabEngine/MatlabEngine.pdf for more help regarding C++ and MATLAB.
The compilation process in C/C++ is divided in two phases:
First, the compilation where source code is transformed into machines code with multiples object files (.o or .obj).
Then, the link to transform object files into a single executable file (.dll or .exe).
C/C++ programs that run matlab engine need three things:
1> A compiler that is compatible with matlab engine.
2> Reference to API header files('.h' for c or '.hpp' for c++) for compilation.
3> Reference to the libraries('.lib' for windows,'.so' for linux) for external symbol link.
You can see comptatible linux based system compiler here.
The GCC C/C++ 4.9.x is compatible so you can use g++.
As this pdf suggested, the API header files should be there $matlabroot/extern/include and the .so files should be in $matlabroot/
bin/glnax64 where $matlabroot is your matlab install folder
Set up Environment variables
Open your temnial with ctrl + alt + T and type :
setenv PATH $matlabroot/bin:$matlabroot/sys/os:$PATH
You can then go to the folder where source file is located, let's say $matlabroot/extern/examples/eng_mat/ with the following command :
cd $matlabroot/extern/examples/eng_mat/
You need to do the compilation with :
g++ -c engDemo.cpp -I '$matlabroot/extern/include' -leng -lmat -lmex -lut
After that, a file named engDemo.o should be created.
The -leng -lmat -lmex -lut options are probably needed among other things because of the usage of the matlab interpreter that should be located in $matlabroot/bin
And the external symbol link with :
g++ -o engDemo -L '$matlabroot/bin/glnax64'
Be careful as this path sugested that you are on a x64 architecture machine, if you are not,the path might be slightly different.
Then you can execute your file just by doing ./engDemo
I can't install the matlab engine on the laptot I am using so I'm unable to test the instruction I gave you but It should be done this way.
Hope it helps !!

Why is my ocaml module undefined?

I've got a lexer and parser that I built with ocamllex and menhir, and they work when I #use them at top level, but the modules they constitute are still undefined.
~: ocamlbuild -clean
~: ocamlbuild PhoebeParser.cma PhoebeLexer.cma
ocamlopt.opt unix.cmxa -I /Users/Tim/.opam/system/lib/ocamlbuild /Users/Tim/.opam/system/lib/ocamlbuild/ocamlbuildlib.cmxa myocamlbuild.ml /Users/Tim/.opam/system/lib/ocamlbuild/ocamlbuild.cmx -o myocamlbuild
menhir --infer --raw-depend --ocamldep 'ocamldep.opt -modules' PhoebeParser.mly > PhoebeParser.mly.depends
ocamldep.opt -modules PhoebeAST.ml > PhoebeAST.ml.depends
ocamlc.opt -c -o PhoebeAST.cmo PhoebeAST.ml
menhir --ocamlc ocamlc.opt --infer PhoebeParser.mly
ocamldep.opt -modules PhoebeParser.mli > PhoebeParser.mli.depends
ocamlc.opt -c -o PhoebeParser.cmi PhoebeParser.mli
ocamldep.opt -modules PhoebeParser.ml > PhoebeParser.ml.depends
ocamlc.opt -c -o PhoebeParser.cmo PhoebeParser.ml
ocamlc.opt -a PhoebeAST.cmo PhoebeParser.cmo -o PhoebeParser.cma
ocamldep.opt -modules PhoebeLexer.mli > PhoebeLexer.mli.depends
ocamlc.opt -c -o PhoebeLexer.cmi PhoebeLexer.mli
ocamllex.opt -q PhoebeLexer.mll
ocamldep.opt -modules PhoebeLexer.ml > PhoebeLexer.ml.depends
ocamlc.opt -c -o PhoebeLexer.cmo PhoebeLexer.ml
ocamlc.opt -a PhoebeAST.cmo PhoebeParser.cmo PhoebeLexer.cmo -o PhoebeLexer.cma
~: cd _build/
~/_build: ocaml
OCaml version 4.04.0
# PhoebeParser.phoebe_spec;;
Characters -1--1:
PhoebeParser.phoebe_spec;;
Error: Reference to undefined global `PhoebeParser'
# PhoebeLexer.phoebe_lexer;;
Characters -1--1:
PhoebeLexer.phoebe_lexer;;
Error: Reference to undefined global `PhoebeLexer'
#
What am I doing wrong?
Your modules are compiled and archived in PhoebeLexer.cma and PhoebeParser.cma files. Each module also has an accompanying .cmi file, that describes its interface. To load a module to the top-level you can use #load or #load_rec directives. The #use directive is not useful, as it operates on a source level (it can be seen as a shortcut for copy-pasting).
So, in your case the top-level interaction should look like this (assuming that are starting the top-level in the _build folder):
# #load "PhoebeLexer.cma";;
# #load "PhoebeParser.cma";;
What's the difference between a module I can #load and a module I can Open?
I like concrete questions!
When you're opening a module M, the toplevel is searching for a file m.cmi in the current directory, in the directory where OCaml is installed, and in all directories added explicitly with the #directory directive. The cmi file contains a machine readable condensed module interface (you may think of it as a compiled module interface). This file defines a type of a loaded module. And you can access types of a module without even loading the module. To get the definitions of a module, you need to load the implementation. That is stored either in cmo (compiled module object file) or cma (compiled module archive). A cma file is just a container for multiple cmo. A cmo file contains actual code, that can be loaded and linked with the main program (with the toplevel program in this case).
As you may noticed, an interface and an implementation are completely different entities, that can be loaded independently. The interface is looked up implicitely, you do not need to load it manually, but sometimes you either need to change a directory (by loading the toplevel in a particular directory, or by using the #cd directive), or by adding a directory to the search paths with the #directory directive. Implementations should be always loaded explicitly with the #load directive.
If cmi is available, but an implementation is not loaded, then you will get some Undefined value error. If cmi is not available then an attempt to access to the value declared in the interface of a module with missing cmi file will yell an Unbound value error (even if you loaded the module archive itself).
To summarize: interface describes what is available, implementation defines where it is available. If the value is not in the interface, then it is unbound; if the value is in the interface, but the definition is not found, then it is undefined.