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=1.7 required=5.0 tests=AWL,DNS_FROM_RFC_POST, 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 mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by yquem.inria.fr (Postfix) with ESMTP id 7BA6DBBC4 for ; Tue, 14 Apr 2009 16:06:10 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AvwBAGM15EnRVcbskGdsb2JhbACVTz8BAQEBCQkMBxEDqBWBCY9xAQMBA4N5Bg X-IronPort-AV: E=Sophos;i="4.40,185,1238968800"; d="scan'208";a="26224658" Received: from rv-out-0506.google.com ([209.85.198.236]) by mail3-smtp-sop.national.inria.fr with ESMTP; 14 Apr 2009 16:06:09 +0200 Received: by rv-out-0506.google.com with SMTP id f6so15577235rvb.57 for ; Tue, 14 Apr 2009 07:06:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:in-reply-to:references :date:message-id:subject:from:to:content-type :content-transfer-encoding; bh=WdVLmTobMtKY6pxbYjIIlxcXMzXkDRVczituabimxZo=; b=rp8IBHeCzssJd62eqP2NxP/XeX1EJYwPyrLN0rxqj1lz+8nLjAWNH+/wJEwiT9jvs+ ZCAke1IUThcV7swaqfhYD3YD5Mq9dsTQ8Q23dr8kCNHVY7eloAQMIB53+TzG19kh92o5 s8/+k1mEbJt7+24MRO/8vyeE2yjhpb8IPDAgQ= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; b=lfzQXI/O4DASMqX4lQYEgGieVXlbsbbzj6btmH302RrZfHiFRh+hnn7pdRI9PYdTwQ v1FkPhLgTiSfZcX4BWE5QADE+DxPT/zwWC+jjaUlWsHCOOZcaRC9lpcGzSc3vZV0VAFY /93Nv/AYhrIdACzdxowZyUsF1b1jd/Rc1gvAQ= MIME-Version: 1.0 Received: by 10.142.82.13 with SMTP id f13mr3088608wfb.290.1239717967808; Tue, 14 Apr 2009 07:06:07 -0700 (PDT) In-Reply-To: <9af41d0e0904140451l5a3a0207vb5bd7532a35bbc4e@mail.gmail.com> References: <9af41d0e0904140451l5a3a0207vb5bd7532a35bbc4e@mail.gmail.com> Date: Tue, 14 Apr 2009 18:06:07 +0400 Message-ID: <90823c940904140706i512e4fe0o1d223ec77d6bf478@mail.gmail.com> Subject: Re: [Caml-list] C wrappers for Ocaml functions From: Dmitry Bely To: Caml List Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable 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 On Tue, Apr 14, 2009 at 3:51 PM, Tim Leek wrote: > 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 list= s > 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 love > 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. =A0The = 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 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 pas= s > 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. > > 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 incanta= tions > 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 =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 > #include > #include > > 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_ > closure, 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 > > 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) { > =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 i= s > mad at me. Why am I having to add math library? =A0Again, 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 =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' (...) 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