Version française
Home     About     Download     Resources     Contact us    
Browse thread
embedding ocaml from C++ -- PODs
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Richard Jones <rich@a...>
Subject: Re: [Caml-list] embedding ocaml from C++ -- PODs
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