Version française
Home     About     Download     Resources     Contact us    
Browse thread
C wrappers for Ocaml functions
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Tim Leek <trleek@g...>
Subject: C wrappers for Ocaml functions
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
% 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'
ht.a(floats.o): In function `caml_atan_float':
(.text+0x1c5): undefined reference to `atan'
ht.a(floats.o): In function `caml_acos_float':
(.text+0x1dc): undefined reference to `acos'
ht.a(floats.o): In function `caml_asin_float':
(.text+0x1f3): undefined reference to `asin'
ht.a(floats.o): In function `caml_tanh_float':
(.text+0x20a): undefined reference to `tanh'
ht.a(floats.o): In function `caml_tan_float':
(.text+0x221): undefined reference to `tan'
ht.a(floats.o): In function `caml_cosh_float':
(.text+0x238): undefined reference to `cosh'
ht.a(floats.o): In function `caml_cos_float':
(.text+0x24f): undefined reference to `cos'
ht.a(floats.o): In function `caml_sinh_float':
(.text+0x266): undefined reference to `sinh'
ht.a(floats.o): In function `caml_sin_float':
(.text+0x27d): undefined reference to `sin'
ht.a(floats.o): In function `caml_power_float':
(.text+0x298): undefined reference to `pow'
ht.a(floats.o): In function `caml_sqrt_float':
(.text+0x2bf): undefined reference to `sqrt'
ht.a(floats.o): In function `caml_log10_float':
(.text+0x400): undefined reference to `log10'
ht.a(floats.o): In function `caml_log_float':
(.text+0x417): undefined reference to `log'
ht.a(floats.o): In function `caml_fmod_float':
(.text+0x551): undefined reference to `fmod'
ht.a(floats.o): In function `caml_floor_float':
(.text+0x568): undefined reference to `floor'
ht.a(floats.o): In function `caml_exp_float':
(.text+0x57f): undefined reference to `exp'
ht.a(ht.o): In function `caml_program':
(.text+0x46): undefined reference to `camlHt__entry'
ht.a(ht.o): In function `caml_globals':
(.data+0x2e0): undefined reference to `camlHt'
ht.a(ht.o): In function `caml_data_segments':
(.data+0x410): undefined reference to `camlHt__data_begin'
ht.a(ht.o): In function `caml_data_segments':
(.data+0x418): undefined reference to `camlHt__data_end'
ht.a(ht.o): In function `caml_code_segments':
(.data+0x488): undefined reference to `camlHt__code_begin'
ht.a(ht.o): In function `caml_code_segments':
(.data+0x490): undefined reference to `camlHt__code_end'
ht.a(ht.o): In function `caml_frametable':
(.data+0x4d8): undefined reference to `camlHt__frametable'
collect2: ld returned 1 exit status



-- 
When  I see an adult on a bicycle, I do not despair for the future of the
human race. - H. G.Wells