[
Home
]
[ Index:
by date
|
by threads
]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: | 2009-04-14 (14:06) |
From: | Dmitry Bely <dmitry.bely@g...> |
Subject: | Re: [Caml-list] C wrappers for Ocaml functions |
On Tue, Apr 14, 2009 at 3:51 PM, Tim Leek <trleek@gmail.com> wrote: > Hello. Not sure if this should have gone to beginners or the regular > list. Also not sure if its been answered before. If so, please > redirect me! I did a bunch of searching both on google and in the lists > and couldn't find the answers I needed. So here goes. > > I have written a blob of code in Ocaml that I like very much. I'd love > to keep it in ocaml and not have to worry about things like memory leaks > and so on. However, much of what I do is in C and can't be in Ocaml. > So I am investigating packing my nice Ocaml code into a library and > writing C bindings so that I can talk to it. > > Virtually all of the tutorials out there and documentation cover how to > create Ocaml bindings to a C library. I don't want to do that. The few > examples I have found that are relevant are toy ones. How to write C > bindings to an Ocaml "fib" function, e.g. In particular, I have found > none that cover how to obtain pointers to OCaml function return values > that are not strings or ints, how to store them in C-land, and how to pass > them back to Ocaml as parameters. > > Let's take as a concrete example the following: creating C bindings for > a simple hash table mapping string keys to integer values. If I can > generate bindings for this that work I should be able to do so for the > library I really care about. > > Here's what I put together for the hash table slightly-less-than-toy > example. It doesn't even compile. [Oddly, with very similar incantations > my own code does compiles but then segfaults inside one of the Ocaml fns.] > Any help much appreciated! > > -Tim > > > 1. The implementation. > > % cat ht.ml > > type ht = (string,int) Hashtbl.t > > let create () : ht = Hashtbl.create 100 > > let add (table:ht) key valu = Hashtbl.add table key valu > > let mem (table:ht) key = Hashtbl.mem table key > > let remove (table:ht) key = if (Hashtbl.mem table key) then > Hashtbl.remove table key > > let _ = Callback.register "create" create > > let _ = Callback.register "add" add > > let _ = Callback.register "mem" mem > > let _ = Callback.register "remove" remove > > 2. The wrappers > > % cat ht_wrap.c > #include <caml/mlvalues.h> > #include <caml/callback.h> > #include <caml/alloc.h> > > void *ht_create (void) { > static value *create_closure = NULL; > if (create_closure == NULL) > create_closure = caml_named_value("create"); > return ((void *) (caml_callback(*create_ > closure, Val_unit))); > } > > void ht_add (void *ht, char *key, int val) { > static value *add_closure = NULL; > if (add_closure == NULL) > add_closure = caml_named_value("add"); > caml_callback3(*add_closure, (value) ht, caml_copy_string(key), > Val_int(val)); > } > > void ht_mem (void *ht, char *key) { > static value *mem_closure = NULL; > if (mem_closure == NULL) > mem_closure = caml_named_value("mem"); > caml_callback2(*mem_closure, (value) ht, caml_copy_string(key)); > } > > void ht_remove (void *ht, char *key) { > static value *remove_closure = NULL; > if (remove_closure == NULL) > remove_closure = caml_named_value("remove"); > caml_callback2(*remove_closure, (value) ht, caml_copy_string(key)); > } > > > 3. Header file for those wrappers > > % cat ht.h > > void *ht_create (void); > void ht_add (void *ht, char *key, int val); > void ht_mem (void *ht, char *key); > void ht_remove (void *ht, char *key); > > 4. The test program, with main() function. > > % cat ht_test.c > #include <stdio.h> > #include "ht.h" > > int main (int argc, char **argv) { > void *ht; > > caml_startup(argv); > > ht = ht_create(); > ht_add(ht, "foo", 1); > ht_add(ht, "foo", 1); > ht_add(ht, "bar", 1); > ht_remove(ht, "foo"); > } > > > 5. And this is how I am attempting to compile it. Note that error I'm > getting here is in link. If I add "-lm" it gets less noisy but still is > mad at me. Why am I having to add math library? Again, help!! > > % ocamlopt -output-obj -o ht.o ht.ml Wrong! You cannot specify ht.o as an output as ht.o is an intermediate result of ht.ml compilation. Activate -verbose flag and you'll see. Replace it with something like ocamlopt -output-obj -o ht_out.o ht.ml > % ocamlopt -c ht_wrap.c > % cp /usr/lib/ocaml/3.10.0/libasmrun.a ./ht.a > % ar r ht.a ht_wrap.o ht.o > % gcc -o htt ht_test.c ht.a -lcurses > ht.a(floats.o): In function `caml_ceil_float': > (.text+0x193): undefined reference to `ceil' > ht.a(floats.o): In function `caml_atan2_float': > (.text+0x1ae): undefined reference to `atan2' (...) Why simply not to use ocamlopt -c ht_wrap.c gcc -o htt ht_test.c ht_out.o ht_wrap.o -L${OCAMLLIB} -lasmrun -lcurses -lm ? - Dmitry Bely