"ocaml_beginners"::[] two questions about interfacing c and ocaml

View: New views
4 Messages — Rating Filter:   Alert me  

"ocaml_beginners"::[] two questions about interfacing c and ocaml

by Erick Matsen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello everyone----


1. I'm having trouble accessing two dimensional bigarrays from c.

Here's the c code:

CAMLprim value print_00_c(value a_value)
{
  CAMLparam1(a_value);
  int n_rows = Bigarray_val(a_value)->dim[0];
  int n_cols = Bigarray_val(a_value)->dim[1];
  double **a = Data_bigarray_val(a_value);
  printf("%d\t%d\n",n_rows,n_cols);
  printf("%f\n",a[0][0]);
  CAMLreturn(Val_unit);
}


Here's the external declaration:

external print_00 : Gsl_matrix.matrix  -> unit = "print_00_c"


And here's the ocaml code:

let a = Gsl_matrix.create ~init:0. 5 5 in
Fam_gsl_matvec.print_00 a;

This program prints
5       5
as it should, but then segfaults.

What's going on here? The equivalent code for one dim bigarrays works great.


2. How would I make a custom toplevel that includes this c code? Do I need to
make a library for it first? It does make sense that one can't compile c .o
files into bytecode. My myocamlbuild.ml looks like (thanks, Dario T!):

open Ocamlbuild_plugin;;
open Command;;

dispatch begin function
  | Before_options ->
      Options.ocaml_lflags := ["-ccopt"; "-static"];
  | After_rules ->
      flag ["ocaml"; "byte"; "link"; "top";] (S[A"-custom"]);
      dep ["ocaml"; "link";] ["linear_c.o"];
      ocaml_lib ~extern:true ~dir:"+gsl" "gsl";
  | _ -> ()
end;;

and
      dep ["ocaml"; "byte"; "link"; "top";] ["linear_c.o"];

doesn't help either.


Thanks,

Erick

Re: "ocaml_beginners"::[] two questions about interfacing c and ocaml

by Richard Jones-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Oct 08, 2009 at 06:32:11AM -0700, Erick Matsen wrote:

> Hello everyone----
>
>
> 1. I'm having trouble accessing two dimensional bigarrays from c.
>
> Here's the c code:
>
> CAMLprim value print_00_c(value a_value)
> {
>   CAMLparam1(a_value);
>   int n_rows = Bigarray_val(a_value)->dim[0];
>   int n_cols = Bigarray_val(a_value)->dim[1];
>   double **a = Data_bigarray_val(a_value);

This isn't how arrays work, either in OCaml or in C.

>   printf("%d\t%d\n",n_rows,n_cols);
>   printf("%f\n",a[0][0]);

You just can't write a[0][0].  Read about C multidimensional arrays
and you'll see why.

Rich.

--
Richard Jones
Red Hat

Re: "ocaml_beginners"::[] two questions about interfacing c and ocaml

by ygrek-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, 8 Oct 2009 06:32:11 -0700
Erick Matsen <ematsen@...> wrote:

> 1. I'm having trouble accessing two dimensional bigarrays from c.
>
> Here's the c code:
>
> CAMLprim value print_00_c(value a_value)
> {
>   CAMLparam1(a_value);
>   int n_rows = Bigarray_val(a_value)->dim[0];
>   int n_cols = Bigarray_val(a_value)->dim[1];
>   double **a = Data_bigarray_val(a_value);
>   printf("%d\t%d\n",n_rows,n_cols);
>   printf("%f\n",a[0][0]);
>   CAMLreturn(Val_unit);
> }
 
double** is a pointer to pointer. While the bigarray layout is flat. So this will work :

CAMLprim value print_00_c(value a_value)
{
  CAMLparam1(a_value);
  int n_rows = Bigarray_val(a_value)->dim[0];
  int n_cols = Bigarray_val(a_value)->dim[1];
  double* a = Data_bigarray_val(a_value);
  printf("%d\t%d\n",n_rows,n_cols);
  printf("%f\n",a[0]);
  CAMLreturn(Val_unit);
}
 
> 2. How would I make a custom toplevel that includes this c code? Do I need to
> make a library for it first? It does make sense that one can't compile c .o
> files into bytecode. My myocamlbuild.ml looks like (thanks, Dario T!):

I believe making cma is a "proper way". But you can easily force linking single object file
with myocamlbuild.ml :

      flag ["ocaml"; "link";] (S[A"linear_c.o"]);

NB: `dep` just adds the dependency for rebuild checking.
BTW -ccopt -static is not needed for ocaml by itself.

$ rlwrap ./test.top
        Objective Caml version 3.11.1

# open Test;;
# test();;
5 5
0.000000
- : unit = ()
#


--
 ygrek
 http://ygrek.org.ua

Re: "ocaml_beginners"::[] two questions about interfacing c and ocaml

by Erick Matsen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello ocamlers---


This is a wrap-up of my questions. Thank you very much for the help.


1. Bigarrays, as a number of people noted, are flat when seen from the
outside. That means that to access the i,j'th element, it appears that
one should do something like (i*n_cols)+j.

One of the sources of my confusion with this was
http://en.wikipedia.org/wiki/C_syntax#Multidimensional_arrays
which makes it seem as if there is more to the story than the above.


2. Ocamlbuild is finally doing what I want! Andres Varon and ygrek
were very helpful here.

I ended up going with Andres' solution, which as I understand it is to
make a DLL, then incorporate that directly using -l.

To make a DLL, I just had to make a .clib file like so
[stoke:~/pplacer/ocaml]$ cat libpplacercside.clib
linear_c.o
[stoke:~/pplacer/ocaml]$

where linear_c.c contains the routines I would like (pplacer is the
name of my software).

Now the ocamlbuild line

dep  ["link"; "ocaml"; "use_pplacer"] ["libpplacercside.a"];

makes dllpplacercside.so. The use_pplacer tag shows up as one might expect:

<*.{byte,native,top,p.native}>: use_gsl, use_str, use_unix,
use_bigarray, use_pplacer

I want the binaries to be self-contained, so I choose static linking
(separate issue from the above).


In recap,

[stoke:~/pplacer/ocaml]$ cat _tags
<common>: include
<*.{byte,native,top,p.native}>: use_gsl, use_str, use_unix,
use_bigarray, use_pplacer
<**/*.ml>: use_gsl, warn_Z
[stoke:~/pplacer/ocaml]$ cat myocamlbuild.ml

open Ocamlbuild_plugin;;
open Command;;


dispatch begin function
  | Before_options ->
      (* use static linking for native binaries *)
      flag ["link"; "ocaml"; "native";] (S[A"-ccopt"; A"-static"]);
  | After_rules ->
      (* custom: incorporate libraries into bytecode *)
      flag ["link"; "ocaml"; "byte"] (A"-custom");
      (* link with libpplacercside given use_pplacer tag *)
      flag ["link"; "ocaml"; "use_pplacer"]
        (S[A"-cclib"; A"-lpplacercside"; A"-cclib"; A"-L.";]);
      (* make libpplacercside when needed *)
      dep  ["use_pplacer"] ["libpplacercside.a"];
      (* automatically include gsl when the use_gsl tag is given in _tags *)
      ocaml_lib ~extern:true ~dir:"+gsl" "gsl";
  | _ -> ()
end;;


Again, thanks for helping out this novice.


Erick

On Thu, Oct 8, 2009 at 9:48 AM, Richard Jones <rich@...> wrote:

>
>
>
> On Thu, Oct 08, 2009 at 06:32:11AM -0700, Erick Matsen wrote:
> > Hello everyone----
> >
> >
> > 1. I'm having trouble accessing two dimensional bigarrays from c.
> >
> > Here's the c code:
> >
> > CAMLprim value print_00_c(value a_value)
> > {
> > CAMLparam1(a_value);
> > int n_rows = Bigarray_val(a_value)->dim[0];
> > int n_cols = Bigarray_val(a_value)->dim[1];
> > double **a = Data_bigarray_val(a_value);
>
> This isn't how arrays work, either in OCaml or in C.
>
> > printf("%d\t%d\n",n_rows,n_cols);
> > printf("%f\n",a[0][0]);
>
> You just can't write a[0][0]. Read about C multidimensional arrays
> and you'll see why.
>
> Rich.
>
> --
> Richard Jones
> Red Hat
>