caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* embedding ocaml from C++ -- PODs
@ 2007-07-02 11:06 Oliver Kania
  2007-07-02 11:48 ` [Caml-list] " Richard Jones
  2007-07-02 11:49 ` Thomas Fischbacher
  0 siblings, 2 replies; 5+ messages in thread
From: Oliver Kania @ 2007-07-02 11:06 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 705 bytes --]

Hello,
the OCAML documentation gives good explanation about how call OCAML
functions from C.
However , what I want to do is the following. I have a C structure with many
fields.
I want to be able to initialize this structure both in C and in Ocaml and
want access to the same instance from both languages.
The structure could be a global object in OCAML and C. The important point
is that I want to have access to the very same
data and not to any copies, which means I want to pass a reference from
OCAML to C or vice versa.
More generally speaking, I would like to create objects in C and pass
references to these objects to the OCAML side and vice versa.
Its all about data flow between the two sides.

[-- Attachment #2: Type: text/html, Size: 737 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] embedding ocaml from C++ -- PODs
  2007-07-02 11:06 embedding ocaml from C++ -- PODs Oliver Kania
@ 2007-07-02 11:48 ` Richard Jones
       [not found]   ` <1262c4ee0707020509h48d43e24s5e8902810cae7985@mail.gmail.com>
  2007-07-02 11:49 ` Thomas Fischbacher
  1 sibling, 1 reply; 5+ messages in thread
From: Richard Jones @ 2007-07-02 11:48 UTC (permalink / raw)
  To: Oliver Kania; +Cc: caml-list

On Mon, Jul 02, 2007 at 01:06:03PM +0200, Oliver Kania wrote:
> Hello,
> the OCAML documentation gives good explanation about how call OCAML
> functions from C.
> However , what I want to do is the following. I have a C structure with many
> fields.
> I want to be able to initialize this structure both in C and in Ocaml and
> want access to the same instance from both languages.
> The structure could be a global object in OCAML and C. The important point
> is that I want to have access to the very same
> data and not to any copies, which means I want to pass a reference from
> OCAML to C or vice versa.
> More generally speaking, I would like to create objects in C and pass
> references to these objects to the OCAML side and vice versa.
> Its all about data flow between the two sides.

This is possible, although you need to understand the OCaml runtime
fully to be able to do it.  Here are a few questions and comments to
get the ball rolling for you:

What sort of data is going to be stored in this structure?  (ints,
floats, arrays, structures linked with pointers, bitfields, ...?)

How are the structure elements aligned?  Can you choose the alignment?

Can you change the C fields to suit OCaml?  For example, if you want
to store native ints directly in the structure, then it's going to be
a lot simpler if you store them as OCaml ints (shift left one place
with the bottom bit set) instead of C ints, but if you do this you'll
have (a) slightly more work to do on the C side, and (b) one less bit
to play with.

You can share C pointers with OCaml directly, but beware of this
problem which may bite you:
http://caml.inria.fr/pub/old_caml_site/caml-list/1415.html

Rich.

-- 
Richard Jones
Red Hat


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] embedding ocaml from C++ -- PODs
  2007-07-02 11:06 embedding ocaml from C++ -- PODs Oliver Kania
  2007-07-02 11:48 ` [Caml-list] " Richard Jones
@ 2007-07-02 11:49 ` Thomas Fischbacher
  1 sibling, 0 replies; 5+ messages in thread
From: Thomas Fischbacher @ 2007-07-02 11:49 UTC (permalink / raw)
  To: Oliver Kania; +Cc: caml-list


Oliver Kania wrote:

> the OCAML documentation gives good explanation about how call OCAML 
> functions from C.
> However , what I want to do is the following. I have a C structure with 
> many fields.
> I want to be able to initialize this structure both in C and in Ocaml 
> and want access to the same instance from both languages.
> The structure could be a global object in OCAML and C. The important 
> point is that I want to have access to the very same
> data and not to any copies, which means I want to pass a reference from 
> OCAML to C or vice versa.
> More generally speaking, I would like to create objects in C and pass 
> references to these objects to the OCAML side and vice versa.
> Its all about data flow between the two sides.

Well, all accessors should conceptually be functions, not just some
weird special syntax. Perl "resolved" that issue through the
introduction of "magic", Python has something equivalent, and in Lisp,
the question des not arise in the first place, because all accessors
already are functions.

Just wrap up a couple of set_ and get_ functions and you will be fine.

-- 
best regards,
Thomas Fischbacher
tf@functionality.de


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] embedding ocaml from C++ -- PODs
       [not found]   ` <1262c4ee0707020509h48d43e24s5e8902810cae7985@mail.gmail.com>
@ 2007-07-03  8:59     ` Richard Jones
  2007-07-05 20:43       ` Oliver Kania
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Jones @ 2007-07-03  8:59 UTC (permalink / raw)
  To: Oliver Kania, caml-list

On Mon, Jul 02, 2007 at 02:09:41PM +0200, Oliver Kania wrote:
> Hi there,
> yes, basically I can use ocaml-types.
> I guess I will have to "unwrap" them on the C-side.
> I have a favor to ask from you:
> Could you please post a small example with, lets say
> a strucutre with 4 members, showing both the C and the ocaml-side
> modifying it ? I do not find the Ocaml documentatino to be very instructive
> concerning this topic.

Please CC replies to the list.

Here's an example showing a four element structure shared between C
and OCaml.  All the fields except the float can be modified on the
OCaml side (you can get around that restriction by keeping any floats
you need in a separate float-only structure).  All fields can be
modified on the C side.

It's only very lightly tested, so probably contains bugs.

Rich.

------------------------------------------------------------ st.ml
open Printf

(* All fields in struct4 are mutable from the OCaml side, except
 * the boxed float.  If you want to share and update floats, then
 * it's better to use a separate float-only array or structure
 * for them, so they are stored unboxed and can be directly
 * modified from OCaml.
 *)
type struct4 = {
  mutable memb1 : int;
  mutable memb2 : enum4;
  memb3 : float;
  mutable memb4 : int;
}
and enum4 = Is0 | Is1 | Is2 | Is3

let string_of_enum4 = function
  | Is0 -> "Is0" | Is1 -> "Is1" | Is2 -> "Is2" | Is3 -> "Is3"

let next_enum4 = function
  | Is0 -> Is1 | Is1 -> Is2 | Is2 -> Is3 | Is3 -> Is0

external create_struct4_from_c : unit -> struct4 = "create_struct4"

external print_struct4_from_c : struct4 -> unit = "print_struct4"

external update_struct4_from_c : struct4 -> unit = "update_struct4"

let print_struct4_from_ocaml data =
  printf "OCaml: memb1 = %d\n" data.memb1;
  printf "OCaml: memb2 = %s\n" (string_of_enum4 data.memb2);
  printf "OCaml: memb3 = %f\n" data.memb3;
  printf "OCaml: memb4 = %d\n" data.memb4;
  flush stdout

let update_struct4_from_ocaml data =
  data.memb1 <- data.memb1 + 1;
  data.memb2 <- next_enum4 data.memb2;
  data.memb4 <- data.memb4 + 2

let () =
  let data = create_struct4_from_c () in
  while true do
    print_struct4_from_c data;
    print_struct4_from_ocaml data;
    printf "* updating struct4 from C\n"; flush stdout;
    update_struct4_from_c data;
    print_struct4_from_c data;
    print_struct4_from_ocaml data;
    printf "* updating struct4 from OCaml\n"; flush stdout;
    update_struct4_from_ocaml data;
    Gc.compact ()
  done


------------------------------------------------------------ st_c.c
#include <stdio.h>

#include <caml/config.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>

struct struct4 {
  value header;			/* CAML header word. */
  value memb1;
  value memb2;
  value memb3;			/* NB: boxed */
  value memb4;
};

#if defined(ARCH_ALIGN_DOUBLE)
#warn "this code probably won't work on 32 bit ARCH_ALIGN_DOUBLE platforms"
#endif
struct memb3 {			/* Storage for a float. */
  value header;			/* CAML header word. */
  double d;			/* The float itself. */
};

CAMLprim value
create_struct4 (value unitv)
{
  CAMLparam1 (unitv);
  struct struct4 *data;
  struct memb3 *memb3;

  /* Allocate on the C heap and return a raw pointer.  For
   * provisos about this, see:
   * http://caml.inria.fr/pub/old_caml_site/caml-list/1415.html
   * http://caml.inria.fr/pub/ml-archives/caml-list/2006/09/977818689f4ceb2178c592453df7a343.en.html
   */
  data = malloc (sizeof *data);

  /* We must initialise at least the header and the boxed memb3.
   * Best to do all fields.
   */
  data->header = 4 << 10;
  data->memb1 = Val_int (0);
  data->memb2 = Val_int (0);	/* Is0 */

  memb3 = malloc (sizeof *memb3);
  memb3->header = 1 << 10 | Double_tag;
  memb3->d = 0.;
  data->memb3 = (value) &memb3->d;

  data->memb4 = Val_int (0);

  CAMLreturn ((value) &data->memb1);
}

CAMLprim value
print_struct4 (value datav)
{
  CAMLparam0 ();		/* datav isn't on the CAML heap. */
  struct struct4 *data = (struct struct4 *) Hp_val (datav);
  struct memb3 *memb3 = (struct memb3 *) Hp_val (data->memb3);

  printf ("    C: memb1 = %d\n", Int_val (data->memb1));
  printf ("    C: memb2 = Is%d\n", Int_val (data->memb2));
  printf ("    C: memb3 = %f\n", memb3->d);
  printf ("    C: memb4 = %d\n", Int_val (data->memb4));
  fflush (stdout);

  CAMLreturn (Val_unit);
}

CAMLprim value
update_struct4 (value datav)
{
  CAMLparam0 ();		/* datav isn't on the CAML heap. */
  struct struct4 *data = (struct struct4 *) Hp_val (datav);
  struct memb3 *memb3 = (struct memb3 *) Hp_val (data->memb3);
  int i;

  data->memb1 = Val_int (Int_val (data->memb1) + 1);
  i = Int_val (data->memb2);
  i++;
  if (i > 3) i = 0;
  data->memb2 = Val_int (i);
  memb3->d += 0.1;
  data->memb4 = Val_int (Int_val (data->memb4) + 2);

  CAMLreturn (Val_unit);
}

------------------------------------------------------------ Makefile
CC	:= gcc
CFLAGS	:= -Wall -Werror -I$(shell ocamlc -where)

all:	test

test:	st.cmx st_c.o
	ocamlopt -o $@ $^

st.cmx:	st.ml
	ocamlopt -o $@ -c $^

----------------------------------------------------------------------


-- 
Richard Jones
Red Hat


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] embedding ocaml from C++ -- PODs
  2007-07-03  8:59     ` Richard Jones
@ 2007-07-05 20:43       ` Oliver Kania
  0 siblings, 0 replies; 5+ messages in thread
From: Oliver Kania @ 2007-07-05 20:43 UTC (permalink / raw)
  To: Richard Jones; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 5654 bytes --]

thanks !!

On 7/3/07, Richard Jones <rich@annexia.org> wrote:
>
> On Mon, Jul 02, 2007 at 02:09:41PM +0200, Oliver Kania wrote:
> > Hi there,
> > yes, basically I can use ocaml-types.
> > I guess I will have to "unwrap" them on the C-side.
> > I have a favor to ask from you:
> > Could you please post a small example with, lets say
> > a strucutre with 4 members, showing both the C and the ocaml-side
> > modifying it ? I do not find the Ocaml documentatino to be very
> instructive
> > concerning this topic.
>
> Please CC replies to the list.
>
> Here's an example showing a four element structure shared between C
> and OCaml.  All the fields except the float can be modified on the
> OCaml side (you can get around that restriction by keeping any floats
> you need in a separate float-only structure).  All fields can be
> modified on the C side.
>
> It's only very lightly tested, so probably contains bugs.
>
> Rich.
>
> ------------------------------------------------------------ st.ml
> open Printf
>
> (* All fields in struct4 are mutable from the OCaml side, except
> * the boxed float.  If you want to share and update floats, then
> * it's better to use a separate float-only array or structure
> * for them, so they are stored unboxed and can be directly
> * modified from OCaml.
> *)
> type struct4 = {
>   mutable memb1 : int;
>   mutable memb2 : enum4;
>   memb3 : float;
>   mutable memb4 : int;
> }
> and enum4 = Is0 | Is1 | Is2 | Is3
>
> let string_of_enum4 = function
>   | Is0 -> "Is0" | Is1 -> "Is1" | Is2 -> "Is2" | Is3 -> "Is3"
>
> let next_enum4 = function
>   | Is0 -> Is1 | Is1 -> Is2 | Is2 -> Is3 | Is3 -> Is0
>
> external create_struct4_from_c : unit -> struct4 = "create_struct4"
>
> external print_struct4_from_c : struct4 -> unit = "print_struct4"
>
> external update_struct4_from_c : struct4 -> unit = "update_struct4"
>
> let print_struct4_from_ocaml data =
>   printf "OCaml: memb1 = %d\n" data.memb1;
>   printf "OCaml: memb2 = %s\n" (string_of_enum4 data.memb2);
>   printf "OCaml: memb3 = %f\n" data.memb3;
>   printf "OCaml: memb4 = %d\n" data.memb4;
>   flush stdout
>
> let update_struct4_from_ocaml data =
>   data.memb1 <- data.memb1 + 1;
>   data.memb2 <- next_enum4 data.memb2;
>   data.memb4 <- data.memb4 + 2
>
> let () =
>   let data = create_struct4_from_c () in
>   while true do
>     print_struct4_from_c data;
>     print_struct4_from_ocaml data;
>     printf "* updating struct4 from C\n"; flush stdout;
>     update_struct4_from_c data;
>     print_struct4_from_c data;
>     print_struct4_from_ocaml data;
>     printf "* updating struct4 from OCaml\n"; flush stdout;
>     update_struct4_from_ocaml data;
>     Gc.compact ()
>   done
>
>
> ------------------------------------------------------------ st_c.c
> #include <stdio.h>
>
> #include <caml/config.h>
> #include <caml/mlvalues.h>
> #include <caml/memory.h>
>
> struct struct4 {
>   value header;                 /* CAML header word. */
>   value memb1;
>   value memb2;
>   value memb3;                  /* NB: boxed */
>   value memb4;
> };
>
> #if defined(ARCH_ALIGN_DOUBLE)
> #warn "this code probably won't work on 32 bit ARCH_ALIGN_DOUBLE
> platforms"
> #endif
> struct memb3 {                  /* Storage for a float. */
>   value header;                 /* CAML header word. */
>   double d;                     /* The float itself. */
> };
>
> CAMLprim value
> create_struct4 (value unitv)
> {
>   CAMLparam1 (unitv);
>   struct struct4 *data;
>   struct memb3 *memb3;
>
>   /* Allocate on the C heap and return a raw pointer.  For
>    * provisos about this, see:
>    * http://caml.inria.fr/pub/old_caml_site/caml-list/1415.html
>    *
> http://caml.inria.fr/pub/ml-archives/caml-list/2006/09/977818689f4ceb2178c592453df7a343.en.html
>    */
>   data = malloc (sizeof *data);
>
>   /* We must initialise at least the header and the boxed memb3.
>    * Best to do all fields.
>    */
>   data->header = 4 << 10;
>   data->memb1 = Val_int (0);
>   data->memb2 = Val_int (0);    /* Is0 */
>
>   memb3 = malloc (sizeof *memb3);
>   memb3->header = 1 << 10 | Double_tag;
>   memb3->d = 0.;
>   data->memb3 = (value) &memb3->d;
>
>   data->memb4 = Val_int (0);
>
>   CAMLreturn ((value) &data->memb1);
> }
>
> CAMLprim value
> print_struct4 (value datav)
> {
>   CAMLparam0 ();                /* datav isn't on the CAML heap. */
>   struct struct4 *data = (struct struct4 *) Hp_val (datav);
>   struct memb3 *memb3 = (struct memb3 *) Hp_val (data->memb3);
>
>   printf ("    C: memb1 = %d\n", Int_val (data->memb1));
>   printf ("    C: memb2 = Is%d\n", Int_val (data->memb2));
>   printf ("    C: memb3 = %f\n", memb3->d);
>   printf ("    C: memb4 = %d\n", Int_val (data->memb4));
>   fflush (stdout);
>
>   CAMLreturn (Val_unit);
> }
>
> CAMLprim value
> update_struct4 (value datav)
> {
>   CAMLparam0 ();                /* datav isn't on the CAML heap. */
>   struct struct4 *data = (struct struct4 *) Hp_val (datav);
>   struct memb3 *memb3 = (struct memb3 *) Hp_val (data->memb3);
>   int i;
>
>   data->memb1 = Val_int (Int_val (data->memb1) + 1);
>   i = Int_val (data->memb2);
>   i++;
>   if (i > 3) i = 0;
>   data->memb2 = Val_int (i);
>   memb3->d += 0.1;
>   data->memb4 = Val_int (Int_val (data->memb4) + 2);
>
>   CAMLreturn (Val_unit);
> }
>
> ------------------------------------------------------------ Makefile
> CC      := gcc
> CFLAGS  := -Wall -Werror -I$(shell ocamlc -where)
>
> all:    test
>
> test:   st.cmx st_c.o
>         ocamlopt -o $@ $^
>
> st.cmx: st.ml
>         ocamlopt -o $@ -c $^
>
> ----------------------------------------------------------------------
>
>
> --
> Richard Jones
> Red Hat
>

[-- Attachment #2: Type: text/html, Size: 8531 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-07-05 20:43 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-07-02 11:06 embedding ocaml from C++ -- PODs Oliver Kania
2007-07-02 11:48 ` [Caml-list] " Richard Jones
     [not found]   ` <1262c4ee0707020509h48d43e24s5e8902810cae7985@mail.gmail.com>
2007-07-03  8:59     ` Richard Jones
2007-07-05 20:43       ` Oliver Kania
2007-07-02 11:49 ` Thomas Fischbacher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).