From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: *** X-Spam-Status: No, score=3.8 required=5.0 tests=DNS_FROM_RFC_POST,HTML_10_20, HTML_MESSAGE,SPF_NEUTRAL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by yquem.inria.fr (Postfix) with ESMTP id 0CB7CBBC4 for ; Tue, 14 Apr 2009 13:51:34 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgsCAEcV5ElKfSweimdsb2JhbACCVZJ4PwEBAQoJDAcPBacqgQmPUAEDAQODeQY X-IronPort-AV: E=Sophos;i="4.40,184,1238968800"; d="scan'208";a="24553189" Received: from yx-out-2324.google.com ([74.125.44.30]) by mail2-smtp-roc.national.inria.fr with ESMTP; 14 Apr 2009 13:51:33 +0200 Received: by yx-out-2324.google.com with SMTP id 8so1393513yxb.27 for ; Tue, 14 Apr 2009 04:51:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:date:message-id:subject :from:to:content-type; bh=whq3F5PYcJr+Hx2ZpzbVSFR+HOnasYcP6tO0QQkrxKw=; b=DoAKBvfr0VPsCG8oTU7EBzI8FmL3y1II8tRe4B53hq9vOjGy2/KSYrE6GL4QR/qSFr sFoXme2pHrO8Oscjoy3yrmZE307MLSJ8m5KCRi6vjqNl7xfK9qy0jr7AfYtIzrZAvx/H SvZQBCYITJfDub//EifkLLjbx2UC6fWagXSP4= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=q12yQ6ylxngqD3ZkCaSdlSZsLHuueSILZtrvwZ25kEv3GhVjPQyayyP5gvZO9Lr/FB v4fBYtEH6zIDkOTESMufAxMczHw5yYwDpaBMkN+jS+uzaGV2pEbaSadZrloTy7Zoc+4T kTUpXikG//j9Ym0K3+eoLisGZo0AAwt54g3ps= MIME-Version: 1.0 Received: by 10.150.148.7 with SMTP id v7mr14951880ybd.66.1239709892220; Tue, 14 Apr 2009 04:51:32 -0700 (PDT) Date: Tue, 14 Apr 2009 07:51:32 -0400 Message-ID: <9af41d0e0904140451l5a3a0207vb5bd7532a35bbc4e@mail.gmail.com> Subject: C wrappers for Ocaml functions From: Tim Leek To: caml-list@inria.fr Content-Type: multipart/alternative; boundary=000e0cd47c58c019860467827386 X-Spam: no; 0.00; wrappers:01 ocaml:01 ocaml:01 bindings:01 bindings:01 pointers:01 hash:01 hash:01 segfaults:01 hashtbl:01 hashtbl:01 wrappers:01 mlvalues:01 alloc:01 val:01 --000e0cd47c58c019860467827386 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit 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 #include #include 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 #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 --000e0cd47c58c019860467827386 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Hello. =A0Not sure if this should have gone to beginners or the regular
list. =A0Also not sure if its been answered before. =A0If so, please
redirect me! =A0I did a bunch of searching both on google and in the lists<= br> and couldn't find the answers I needed. =A0So here goes.

I have written a blob of code in Ocaml that I like very much. =A0I'd lo= ve
to keep it in ocaml and not have to worry about things like memory leaks and so on. =A0However, 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. =A0I don't want to do that. =A0Th= e few
examples I have found that are relevant are toy ones. =A0How to write C
bindings to an Ocaml "fib" function, e.g. =A0In particular, I hav= e 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. =A0If I can
generate bindings for this that work I should be able to do so for the
library I really care about.=A0

Here's what I put together for the hash table slightly-less-than-toy example. =A0It doesn't even compile.=A0 [Oddly, with very similar incan= tations
my own code does compiles but then segfaults inside one of the O= caml fns.]=A0
Any help much appreciated!

-Tim


1. The implementation.

% cat ht.ml

type ht =3D (string,int) Hashtbl.t

let create () : ht =3D Hashtbl.create 100

let add (table:ht) key valu =3D Hashtbl.add table key valu

let mem (table:ht) key =3D Hashtbl.mem table key

let remove (table:ht) key =3D if (Hashtbl.mem table key) then
Hashtbl.remove table key

let _ =3D Callback.register "create" create

let _ =3D Callback.register "add" add

let _ =3D Callback.register "mem" mem

let _ =3D Callback.register "remove" remove

2. The wrappers

% =A0cat ht_wrap.c
#include <caml/mlvalues.h>
#include <caml/callback.h>
#include <caml/alloc.h>

void *ht_create (void) {
=A0static value *create_closure =3D NULL;
=A0if (create_closure =3D=3D NULL)
=A0 =A0create_closure =3D caml_named_value("create");
=A0return ((void *) (caml_callback(*create_
clos= ure, Val_unit)));
}

void ht_add (void *ht, char *key, int val) {
=A0static value *add_closure =3D NULL;
=A0if (add_closure =3D=3D NULL)
=A0 =A0add_closure =3D caml_named_value("add");
=A0caml_callback3(*add_closure, (value) ht, caml_copy_string(key),
Val_int(val));
}

void ht_mem (void *ht, char *key) {
=A0static value *mem_closure =3D NULL;
=A0if (mem_closure =3D=3D NULL)
=A0 =A0mem_closure =3D caml_named_value("mem");
=A0caml_callback2(*mem_closure, (value) ht, caml_copy_string(key));
}

void ht_remove (void *ht, char *key) {
=A0static value *remove_closure =3D NULL;
=A0if (remove_closure =3D=3D NULL)
=A0 =A0remove_closure =3D caml_named_value("remove");
=A0caml_callback2(*remove_closure, (value) ht, caml_copy_string(key));
}


3. Header file for those wrappers

% cat ht.h

voi= d *ht_create (void);
void ht_add (void *ht, char *key, int val);<= /div>
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) {
=A0void =A0*ht;

=A0caml_startup(argv);

=A0ht =3D ht_create();
=A0ht_add(ht, "foo", 1);
=A0ht_add(ht, "foo", 1);
=A0ht_add(ht, "bar", 1);
=A0ht_remove(ht, "foo");
}


5. And this is how I am attempting to compile it. =A0Note that error I'= m
getting here is in link. =A0If I add "-lm" it gets less noisy but= still is
mad at me. Why am I having to add math library? =A0Again, help!!

% ocamlopt -output-obj -o ht.o = ht.ml
% ocamlopt -c ht_wrap.c
% cp =A0/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 =A0-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 =A0I see an adult on a bicycle,= I do not despair for the future of the human race. - H. G.Wells

--000e0cd47c58c019860467827386--