I was messing around with the OCaml FFI to try to figure out how it goes about inferring the width of a C enum (which I think is implementation-defined for C) and am trying to insert a type of the wrong width to see what blows up at runtime. That's the motivation, but the actual issue I ran into is much more mundane.
I have a simple OCaml file that uses the C FFI to call a trivial function in example.c that converts an enum to an int.
open Printf;;
let (#->) = Ctypes.(#->);;
let returning = Ctypes.returning;;
let foreign = Foreign.foreign;;
(* deliberately use the wrong scalar type for argument *)
let wrong_int64_of_color =
foreign "int_of_color" (Ctypes.int64_t #-> returning Ctypes.int64_t);;
let main () =
printf "%Ld\n" (wrong_int64_of_color (Int64.of_int 100));;
let () = main ();;
I configured opam and installed Ctypes and Ctypes.Foreign
% opam config env | sed -e 's/=.*/=/'
CAML_LD_LIBRARY_PATH=
OPAMUTF8MSGS=
MANPATH=
PERL5LIB=
OCAML_TOPLEVEL_PATH=
PATH=
% opam list | grep ctypes
ctypes 0.6.2 Combinators for binding to C libraries withou
ctypes-foreign 0.4.0 Virtual package for enabling the ctypes.forei
The two usual incantations I use for compiling a simple .ml script have both failed me and I'm out of ideas. ocamlfind and corebuild (which I think is a wrapper on top of ocamlbuild)
ocamlfind can't seem to find ctypes and foreign. However, it doesn't complain that about not being able to locate the packages so I'm guessing ctypes and ctypes.foreign are the correct names for these packages in the weird findlib namespace.
% ocamlfind ocamlopt -package findlib,ctypes,ctypes.foreign -thread call_example.ml
File "_none_", line 1:
Warning 58: no cmx file was found in path for module Foreign, and its interface was not compiled with -opaque
File "call_example.ml", line 1:
Error: No implementations provided for the following modules:
Ctypes referenced from call_example.cmx
Foreign referenced from call_example.cmx
Why can't ocamlfind locate these modules? I have no problem loading them into the toplevel.
─( 22:30:42 )─< command 0
utop # #require "ctypes";;
─( 22:30:42 )─< command 1
utop # open Ctypes;;
─( 22:30:55 )─< command 2
utop # #require "ctypes.foreign";;
─( 22:31:00 )─< command 3
utop # open Ctypes;;
It seems to me that you forget to add -linkpkg ocamlfind option to instruct the compiler actually link the libraries from the packages to build the executable.
Related
I'm trying to use the "Batteries" module, but... it doesnt work!
Here is an example:
open Batteries;;
print_endline (dump [5;4;2]);;
I'm compiling with: opam exec ocamlc main.ml the error message is:
File "main.ml", line 1, characters 5-14:
1 | open Batteries;;
^^^^^^^^^
Error: Unbound module Batteries
and the Batteries module seems installed:
$ opam install Batteries
[NOTE] Package batteries is already installed (current version is 3.0.0).
What am I missing?
Just installing a library is not enough, you have to tell the compiler that you want to link it (the compiler itself doesn't know anything about opam). There are many compilation and configuration tools available for OCaml, here's just one of the ways to build a binary that uses batteries
ocamlbuild -pkg batteries main.native
My problem is similar to this, however, in my case .ocamlinit is set.
Here is my ocaml version.
mymac:Desktop myusr$ ocaml --version
The OCaml toplevel, version 4.08.1
Here is my opam version.
mymac:Desktop myusr$ opam --version
2.0.5
Here is my opam switch.
mymac:Desktop myusr$ opam switch
# switch compiler description
→ 4.08.1 ocaml-base-compiler.4.08.1 4.08.1
default ocaml-base-compiler.4.08.1 default
Here's my .ocamlinit:
mymac:Desktop myusr$ cat ~/.ocamlinit
(* ## added by OPAM user-setup for ocamltop / base ## 3ec62baf6f9c219ae06d9814069da862 ## you can edit, but keep this line *)
#use "topfind";;
(* ## end of OPAM user-setup addition for ocamltop / base ## keep this line *)
#thread;;
#require "core.top";;
#require "core.syntax";;
Here is the evidence that I already have core installed.
mymac:Desktop myusr$ opam install core utop
[NOTE] Package utop is already installed (current version is 2.4.1).
[NOTE] Package core is already installed (current version is v0.12.3).
Here is the sum.ml file from Real World OCaml:
open Core.Std
let rev read_and_accumulate accum =
let line = In_channel.input_line In_channel.stdin in
match line with
| None -> accum
| Some x -> read_and_accumulate (accum +. Float.of_string x)
let () =
printf "Total: %F\n" (read_and_accumulate 0.)
Here's what happens when I try to build it with corebuild:
mymac:Desktop myusr$ corebuild sum.native
+ ocamlfind ocamlc -c -w A-4-33-40-41-42-43-34-44 -strict-sequence -g -bin-annot -short-paths -thread -package core -ppx 'ppx-jane -as-ppx' -o sum.cmo sum.ml
File "sum.ml", line 1, characters 5-13:
1 | open Core.Std
^^^^^^^^
Error: Unbound module Core.Std
Command exited with code 2.
Hint: Recursive traversal of subdirectories was not enabled for this build,
as the working directory does not look like an ocamlbuild project (no
'_tags' or 'myocamlbuild.ml' file). If you have modules in subdirectories,
you should add the option "-r" or create an empty '_tags' file.
To enable recursive traversal for some subdirectories only, you can use the
following '_tags' file:
true: -traverse
<dir1> or <dir2>: traverse
Compilation unsuccessful after building 2 targets (1 cached) in 00:00:00.
Why isn't corebuild linking to the core library? How can I fix this?
The build script loads everything correctly. The module that you're trying to load no longer exists. You're trying to use an old version of the Real World OCaml book together with a very new version of OCaml and Core. The Janestreet Core library has changed a lot since those times. You should either switch to a newer book or downgrade to an older version of OCaml and Core library.
Using modern Core
Since the admission of Dune and module aliases, it is no longer needed to have an extra Std submodule, therefore Janestreet removed it (after a two-year-long deprecation). Therefore, now we're writing
open Core
instead of
open Core.Std (* no longer works *)
The same is true with Core_kernel et alas.
Since OCaml and Janesteet have moved since that time a lot, the newer version of RWO was created with updated examples. It is still a work in progress but looks quite close to be ready. So you can switch to it.
Sticking to older versions of OCaml
If you would like to use the first version of Real World OCaml, then you have to choose a version of OCaml and Janesteet's Core library which are known to be compatible. I failed to find any authoritative recommendations on which version it is better to use with the old book. So I would suggest using OCaml 4.02.3. Then you can install core as usual with opam install core (it should install version 113.33.03), and as far as I remember, it should work with the old book. If you or anyone else is having problems with this version please tell me in the comments section, and I will update this recommendation.
I've installed opam, run opam init, run opam switch 4.06.0 which created a 4.06.0 directory inside ~/.opam, run "eval opam confing env" which exports $OCAML_TOPLEVEL_PATH as ~/.opam/4.06.0/lib/toplevel amongst other things, when launching ocaml I get the dreaded:
$ ocaml
OCaml version 4.06.0
Cannot find file topfind.
Unknown directive `camlp4o'.
#
I've looked at this and this neither of which address my issue and I'm at my wits' end (first time setting up OCaml). This is my ~/.ocamlinit:
(* Added by OPAM. *)
let () =
try Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH")
with Not_found -> ()
;;
#use "topfind"
#camlp4o
#thread
#require "core.top"
#require "core.syntax"
EDIT: Looks like I hadn't installed core, installing core resolved that but now amongst the slew of import diagnostics I get:
Exception:
Invalid_argument
"The ocamltoplevel.cma library from compiler-libs cannot be loaded inside the OCaml toplevel".
And then a bit further down:
Raised at file "pervasives.ml", line 33, characters 25-45
Called from file "toplevel/toploop.ml", line 468, characters 4-128
Called from file "toplevel/topdirs.ml", line 144, characters 10-51
Camlp4 Parsing version 4.06.0
You should run
eval `opam config env`
Note the backticks. They are usually located to the left of the key 1 on most modern keyboards. The command should not output anything, if you see any output it means that you're running it incorrectly. You have to run this command to activate the opam installation every time you start a new shell (unless you've put this command in your shell initialization scripts, like .bashrc)
If the problem persists, then make sure, that you have installed the ocamlfind package,
opam install ocamlfind
What seemed to work for me:
make sure core is installed (opam install core)
make sure camlp4 is installed (opam install camlp4)
Insert Topfind.don't_load ["compiler-libs.toplevel"];; in-between #use "topfind";; and #require "core.top";;, as per this. It is an issue that doesn't appear to be fixed in the latest version of core (0.9.2).
i'm having a problem while trying to compile an ocaml file with ocamlc -o hello hello.ml it gives me this error
Error: Unbound module Core
which is weird because when i use utop and import the core std with open Core.Std;; it does work and import it, any ideas of how to solve this problem ?
Thanks in advance
open Core.Std does not really import core, it just puts its values in scope so that you can refer to Core.Std.x as just x.
To import it you need to pass it to require the package somehow in your compiler. The easiest way is to use ocamlfind:
ocamlfind ocamlc -package core -linkpkg -o hello hello.ml
The corresponding way to do that in utop is by passing -require core on the command line or #require "core" in the REPL.
From this SO question: List Comprehension in Ocaml?, I could install the comprehension package with opam install pa_comprehension, and use the package in toplevel REPL.
# #require "pa_comprehension";;
# open Batteries;;
# [? 2 * x | x <- 0 -- max_int ; x * x > 3 ?];;
- : int Batteries.Enum.t = <abstr>
Then, how can I compile the code?
Unfortunately, since pa_comprehension package name is not ended with .syntax extension, this is a little bit harder than it should be. (The fact that this issue is still not fixed, shows that using pa_comprehension is not very popular in modern OCaml). So, without the proper extension, we need to do everything manually. If your file is named pr.ml, then the correct invocation is:
$ ocamlbuild -use-ocamlfind -syntax camlp4o -pkg camlp4,pa_comprehension pr.native
If you don't wan't to type it every time, then you can create _tags file, with the following contents:
$ cat _tags
<**/*> : package(camlp4),syntax(camlp4o),package(pa_comprehension)
In that case, the command line spell is a little bit easier:
$ ocamlbuild -use-ocamlfind pr.native