When are OCaml expressions at the top level of a file evaluated? - ocaml

It seems that OCaml runs some expressions at compile-time; e.g., if I write
let (_ : int) = 1 / 0
at the top level of a file, the compiler will fail with an "Uncaught exception: Division_by_zero" error.
Does this mean that these values are computed at compile time in the binary? e.g., if I was using Core, and I wrote
open! Core
let date = Date.today ~zone:(force Time.Zone.local)
would this refer to the date at the time of compilation, or something else, like the date when the program is executed?

I can't reproduce the behavior you describe. Here's what I see:
$ cat dz.ml
let (_ : int) = 1 / 0
$ ocamlc -c dz.ml
$ ocamlopt -c dz.ml
The two OCaml compilers are ocamlc and ocamlopt, and neither of them shows this behavior on my system.
It would help if you give a specific sequence of commands to reproduce what you observe.

Related

Z3 bindings on ocaml

I am currently using ocaml 4.06.0 and I am trying to use the Z3 sat solver. I am using opam's oasis to compile the files (which is building everything successfully). However, when I run the native code produced I am getting the following error: error while loading shared libraries: libz3.so. I tried reinstalling the z3 package but the error still persists. Can anyone help me solve this please because I have no idea what else to try?
Here is what I did just now to install z3 under Ubuntu 18.04.1:
$ opam depext conf-gmp.1
$ opam depext conf-m4.1
These installed gmp and m4 outside of opam. Pretty impressive.
$ opam install z3
Now the z3 library is installed so you can use it from OCaml code. But there are no executables installed (that I can find).
$ export LD_LIBRARY_PATH=~/.opam/4.06.0/lib/z3
$ ocaml -I ~/.opam/4.06.0/lib/z3
OCaml version 4.06.0
# #load "nums.cma";;
# #load "z3ml.cma";;
# let ctx = Z3.mk_context [];;
val ctx : Z3.context = <abstr>
The setting of LD_LIBRARY_PATH is what makes it possible to find libz3.so.
This is as far as I got for now. Maybe this will be helpful.
Update
Here is how I compiled and linked a test program.
$ export LD_LIBRARY_PATH=~/.opam/4.06.0/lib/z3
$ cat tz3.ml
let context = Z3.mk_context []
let solver = Z3.Solver.mk_solver context None
let xsy = Z3.Symbol.mk_string context "x"
let x = Z3.Boolean.mk_const context xsy
let () = Z3.Solver.add solver [x]
let main () =
match Z3.Solver.check solver [] with
| UNSATISFIABLE -> Printf.printf "unsat\n"
| UNKNOWN -> Printf.printf "unknown"
| SATISFIABLE ->
match Z3.Solver.get_model solver with
| None -> ()
| Some model ->
Printf.printf "%s\n"
(Z3.Model.to_string model)
let () = main ()
$ ocamlopt -I ~/.opam/4.06.0/lib/z3 -o tz3 \
nums.cmxa z3ml.cmxa tz3.ml
$ ./tz3
(define-fun x () Bool
true)
$ unset LD_LIBRARY_PATH
$ ./tz3
./tz3: error while loading shared libraries: libz3.so:
cannot open shared object file: No such file or directory
It works--i.e., it says that the trivial formula x can be satisfied by making x be true.
Note: initially I thought the setting of LD_LIBRARY_PATH wasn't necessary here. But in later testing I've found that it is necessary. So that is probably the key to your problem.
It's a little cumbersome and error prone to set LD_LIBRARY_PATH for running your programs. It's good enough for personal testing, but probably not for any kind of wider deployment. There are ways to set the search path for shared libraries at link time.
I hope this helps.

Fortran Fixed Form Line Continuation

I'm always using free form .f90 to write Fortran code, but now I have to use some fixed form .f code. As far as I know, a line continuation in the fixed format can be achieved by putting an arbitrary nonblank, nonzero symbol in column 6.
So this first block should work
x =
& 1
and this second block would fail
x = &
& 1
I have the above conclusion proved by a simple demo code, both compiling with a Makefile and comping with Cmake. If using the first way, everything is good; if the second, compiler will report an error saying it can't understand the "&" after the equal sign.
Now what makes me puzzled is that I have a huge Fortran code in fixed form(.f) by someone else. What's used in this huge code for line continuation is like the second way(which seems not working to me). But the Makefile of that code managed to overcome this issue somehow. That code and Makefile is so large and complicated that I can't manage.
So my question is: How can I let the compiler go through the second way? What magic did the huge Fortran code do? Thanks for any hints.
Update:
I tried to use -ffree-form as suggested, but still get the same error. Here is the demo .f file and Makefile.
main.f
PROGRAM main
IMPLICIT NONE
REAL :: x
REAL :: y
x = &
& 1
WRITE(*,*) x
END PROGRAM main
Makefile:
FC = gfortran
FCFLAGS = -ffree-form
SRCS = main.f
SOBJ = $(SRCS:.f=.o)
EXEC = $(SRCS:.f=)
all: $(EXEC)
%.o: %.f
$(FC) $(FCFLAGS) -c $<

In OCaml 4.03.0 FFI fails to compile with "No implementations provided" Error

I upgraded my ocaml to 4.03.0.
Then, some wrapper libraries failed to build raising "No implemntations provided" Error.
I prepare a small example to explain my situation.
I write a C code in hello_stubs.c
#include<stdio.h>
#include<caml/mlvalues.h>
CAMLprim value caml_print_hello(value unit)
{
printf("Hello\n");
return Val_unit;
}
Next, I prepare the interface file for ocaml, in hello.mli.
external print_hello : unit -> unit = "caml_print_hello"
Then, I code a main program in main.ml
Hello.print_hello();;
To compile these programs, I executed the following commands.
ocamlc -c hello.mli
ocamlc -c hello_stubs.c
ocamlopt -o main main.ml hello_stubs.o
Then, unfortunately, the last command failed with the following error message.
File "_none_", line 1:
Warning 58: no cmx file was found in path for module Hello, and its interface was not compiled with -opaque
File "main.ml", line 1:
Error: No implementations provided for the following modules:
Hello referenced from main.cmx
According to the message,
I've tried ocamlc -opaque hello.mli, but it didn't solve the problem.
I also confirmed that the commands above work fine for ocaml 4.02.3.
Do you know how to compile this example with ocaml 4.03.0?
The fix is easy: create hello.ml of the same contents of hello.mli and compile it and link for main.
I guess this is due to the following change of 4.03.0:
PR#4166, PR#6956: force linking when calling external C primitives
(Jacques Garrigue, reports by Markus Mottl and Christophe Troestler)
The related section of the reference manual should be updated. See http://caml.inria.fr/mantis/view.php?id=7371

OCaml memory profiling with Memprof - TypeRex Utility

My program uses all of available memory, so I wanted to check which functions and abstracts are spoiling my project. I decided to use Memprof, so I installed their compiler and compiled my code with command
ocamlfind ocamlopt -package xml-light unix.cmxa str.cmxa -c -g NKJPxmlbasics.ml NKJP.mli NKJP.ml test.ml
and then run as suggested in tutorial
ocp-memprof --exec ./test
But there is error instead of result:
Error: no memory profiling information found. Possible causes:
- the application was not compiled with memory profiling support;
- the application exited before any major garbage collection was performed.
I even managed once to make it work but I have no idea how it happened
http://memprof.typerex.org/users/97beffbaec332eb7b2a048b94f7a38cf/2015-12-15_17-33-50_ab17218e800fe0a68fc2cfa54c13bfa6_16194/index.html
Is there any way to use this tool properly in this situation? What am I missing?
ocamlfind ... -c ... does not generate any executable. So, the ./test that you are running was probably generated by a previous command, probably without the memprof switch.

OCaml - compiling a program as a library

I have an OCaml program(with a main method - it generates an executable) and I want to use it as a library.
I was compiling my program like this: ocamlc -I someDir -g -unsafe lotsOfCmoFiles -o outputFile and the program works fine.
Now I'm removing the line that makes it an executable(something like let _ = ...) and adding -a parameter to compile command: ocamlc -a -I someDir -g -unsafe lotsOfCmoFiles -o outputFile.cma
But somehow I can't load generated .cma file with ocamltop and ocamlbrowser shows an empty list. When I try to load from ocamltop:
# #load "outputFile.cma";;
Error: Reference to undefined global `Xyz'
And I'm 100% sure that xyz.cmo is included in lotsOfCmoFiles.
Am I giving some parameter wrong while compiling? Or else, what should I do to load my program in ocamltop ? (I'll use this library in another program, I'm giving ocamltop outputs as an example)
Any helps will be appreciated.
EDIT: So I can finally managed to compile and load it thanks to #cago, now I can load my library, and when I don't remove the main let _ = ... line it's automatically run when I load the .cma.
But I still can't open any modules. Strangely, this doesn't raise an exception
open Main
but then when I call a function from module Main:
# someFun;;
Error: Reference to undefined global `Main'
and ocamlbrowse still shows an empty list. now why is that?
EDIT2: I realized open Main doesn't fail because I have a Main module in the same folder(even though I didn't explicitly load it). If I move my .cma file somewhere else and load it, it works(ie. main function runs automatically), but now I can't open any modules even though ocamlobjinfo shows the modules.
EDIT3: -I doesn't help:
$ ocaml
OCaml version 4.00.1
# #load "lib.cma";;
ok
# open Lib;;
Error: Unbound module Lib
#
$ ocaml -I libFolder
OCaml version 4.00.1
# #load "toylib.cma";;
ok
# open Lib;;
# fun;;
Error: Reference to undefined global `Lib'
Some of the cmo in your lotsOfCmoFiles need to know the module Xyz. You need to take care of the dependency between your cmo files.
For example:
toto.ml:
let x = "toto"
titi.ml:
let y = Toto.x ^ " titi"
ocamlc -c toto.ml
ocamlc -c titi.ml
ocamlc -a titi.cmo toto.cmo -o lib.cma (* here is the probleme *)
# #load "lib.cma"
Error: Reference to undefined global `Toto'
Because titi depends on toto so you need to change the order of cmos:
ocamlc -a toto.cmo titi.cmo -o lib.cma
# #load "lib.cma"
# Titi.y;;
- : string = "toto titi"
EDIT:
If your cma is in a subdirectory for example, when you call ocaml you need to specify the path:
ocaml -I subdir/ (* subdir which contains lib.cma *)
# #load "lib.cma"
# Toto.x;;
- : string = "toto"
TL;DR: Make sure you don't have any top-level side-effects in the
I was running into this same kind of trouble. My project would build fine, most modules were available, but there was one module that kept triggering Reference to undefined global. But it was clear that the module was visible to the system: it was showing up in utop's autocomplete list, along with all of it's values, and I could reference it and import it into other modules.
The problem turned out to be an uncaught exception that was being thrown when that module was loaded. The exception was due to an attempt to load a non-existing file. It wouldn't cause problems during complication, but when the module was actually loaded it was breaking and the exception was being swallowed somewhere before I ever saw it.