Unix (Sys) lib with OCaml 4.14

I have a little piece of code p.ml containing a function to time out a function call using the Sys module

#use “unix” ;;
exception Timeout ;;
let timeedout_fun f x timeout =
… Sys. …

timeedout_fun f … ;

that I run at the top level with
ocaml unix.cma p.ml
That’s worked with OCaml 4.13 but no longer work since I updated to 4.14.0 with opam:
Cannot find file unix.
% opam list | grep unix
shows
base-unix unix-errno unix-sys-resource unix-sys-stat unix-time unix-type-representations.

Hope someone has an idea about what to do!

Your issue is the #use "unix";; line. It tries to read a file called unix as if it was a .ml source file, and will fail if there isn’t any.
I’m not sure what you expected that to do, but anyway the Sys library is part of the standard library and doesn’t depend on the Unix library. If you actually need functions from the Unix library, you need to load its code (which you’ve already done by passing unix.cma on the command line) and either prefix its identifiers with Unix. in your code, or use open Unix;; to bring all its values and types in the current scope.

I assume that at some point you actually had an empty or valid unix file lying around, which meant that #use "unix";; didn’t fail. But it’s unlikely to have ever been part of your opam installation, and so I don’t think the 4.14 upgrade is related to your error.

2 Likes

Merci Vincent, it works but I don’t understand why the #use “unix” was working with 4.13 (which in fact does not matter). Thanks again

Note that this will likely no longer work in the future.

The future proof (and general) way to load libraries in the toplevel is to:

#use "topfind"
#require "unix"
2 Likes

In fact, I was looking for a solution that works both when running the program at top level AND compiling it with ocamlc. I did not find a good solution (and use sed to modify the program for top-level/compiler). Any suggestion welcomed!

"topfind" is the toplevel version of ocamlfind .... -package <packagename>. So those two are the “solution that works both ways” you’re looking for, I’d think.

That does not look to work both for top-level execution and compilation. Here is an example:

top-level works
% cat a.ml
(* File a.ml )
print_string “a\n”;;
% cat b1.ml
#use “a.ml”;;
print_string “b\n”;;
% ocaml b1.ml
a
b
% # compilation does not work
% ocamlc a.ml
% ocamlc a.cmo b1.ml
File “b1.ml”, line 2, characters 0-1:
2 | #use “a.ml”;;
^
Error: Syntax error
% # open works with compilation
% cat b2.ml
(
File b2.ml )
open A;;
print_string “b\n”;;
% ocamlc a.cmo b2.ml
% ./a.out
a
b
% # but this does not work for top level
% ocaml b2.ml
b
% # looks like a was ignored
% # would like something working at toplevel and compilation
% cat b3.ml
(
File b3.ml *)
#use “topfind” ;;
#require “a” ;;
print_string “b\n”;;
% ocaml b3.ml
No such package: a
b
cousot1@MacBook-Pro-5 essai % ocamlc a.cmo b3.ml
File “b3.ml”, line 2, characters 0-1:
2 | #use “topfind” ;;
^
Error: Syntax error
% # none works!

It’s a little hard to follow your pasted text. Can you reformat with backticks

like this

to make more obvious what parts are your words, and what are transcripts.

Also though, it seems that you’re now wanting to have something that works for files in the same directory that are either loaded into the toplevel using “#use” or linked ? “#use” is not the same as linking – that would be “#load” which is the same as linking.

top level works
% cat a.ml
print_string “a\n”;;
% cat b1.ml
#use “a.ml”;;
print_string “b\n”;;
% ocaml b1.ml
a
b
compilation does not work
% ocamlc a.ml
% ocamlc a.cmo b1.ml
File “b1.ml”, line 2, characters 0-1:
2 | #use “a.ml”;;
^
Error: Syntax error
open works with compilation
% cat b2.ml
open A;;
print_string “b\n”;;
% ocamlc a.cmo b2.ml
% ./a.out
a
b
but open does not work for top level
% ocaml b2.ml
b
looks like open A was ignored
I would like something working at toplevel and compilation
% cat b3.ml
#use “topfind” ;;
#require “a” ;;
print_string “b\n”;;
% ocaml b3.ml
No such package: a
b
does not work at toplevel
% ocamlc a.cmo b3.ml
File “b3.ml”, line 2, characters 0-1:
2 | #use “topfind” ;;
^
Error: Syntax error
does not work either for compilation

It’s probably a good idea at that point to start reading the manual.
Here are a few sections that should be of interest:

It’s not that long to read, and while it probably won’t solve all of your problems, it should make it easier for us to answer your remaining questions.

Hi Patrick,

I’m not sure that I understand the high level end result you are aiming for, but it looks like you want a single .ml source file that can either be compiled (to a usable executable) or can be processed by the toplevel to enable interactive experimentation with the defined functions. I’m no ocamltop wizard, but for the record, I haven’t ever managed to make that work. Instead the simplest structure that seemed to work the best was to implement the compiled executable putting as much functionality into sub-modules or libraries as possible, and then providing a separate “script” for the toplevel to load the dependencies and bring the desired modules into scope, etc. For example, infer includes such a script that loads (with #require) dependent libraries and opens internal modules to set up a toplevel where one can interact with the analyzer internals.

Cheers, Josh

Have you considered using dune utop? It can build your project and also load your libraries in a REPL session. No need for #use or other directives.

Josh perfectly explains my problem. Essentially the students at this stage do not known yet about modules (theyt will learn later). For them modules are files a.ml, b.ml and c.ml where b.ml uses a.ml and c.ml uses both a.ml and b.ml. I ask them not to put everything in a single file. The #use works well with ocaml but not with ocamlc. So I provide a makefile that will change use into open and vice verra with sed, depending on wether you use ocaml or ocamlc. Obviously I would prefer some (simple) OCaml directives that would work for both cases, I could not find any answer in the manual (the intersection of the top-level and ocamlc chapters looks empty). Dune is OK but a bit too elaborated for a student project. I will try dune utop DIR. Thanks to all.

I’m not sure if it’s better than your current approach, but you could provide an init file that contains all the directives necessary to run the programs, and keep the source files themselves ocamlc-compatible.
Example:

(* init.ml *)
#load "unix.cma";;
#use "a.ml";;
#use "b.ml";;
# Non-interactive version: just run the code
ocaml init.ml
# Interactive version: Start a toplevel with the code loaded
ocaml -init init.ml
2 Likes

Maybe I need 2 inits, another one for compilation.

Is there more than open that you need for compilation? Perhaps it is enough to add some -open Module flags to the ocamlc invocations in the Makefile for compilation, and use an init file for the toplevel.

To compile use something like:

ocamlc -o  myexe str.cma unix.cma mysource.ml

Hm. I would argue that you should start from compilation, and then have a file you can #use (I name my file include_ml) which will load all the relevant modules, set up printers, maybe trace various functions, etc. Something like this: camlp5/include_ml at master · camlp5/camlp5 · GitHub

There’s a ton of stuff going on there. But the nut of it is:

  1. #use “topfind” (a version that understands camlp5 syntaxes)
  2. #require a bunch of modules, including modules that are built in the camlp5 project
  3. then define pretty-printers, etc, etc, etc.

I claim you should never #use files containing actual nontrivial code that you would otherwise compile: compile it and load the object-modules.