Closed akshajgaur closed 3 years ago
The easiest approach is to use a root.
You can use Root.create
to obtain an opaque handle to your list, and expose it to C as a void *
(or as a pointer to an incomplete struct
type to give a little more type safety). When the void *
value is passed back to OCaml you can use Root.get
to retrieve the list:
# let p = Ctypes.Root.create [1;2;3];;
val p : unit Ctypes.ptr = (void*) 0x557bc90e8910
# (Ctypes.Root.get p : int list);;
- : int list = [1; 2; 3]
You'll also need a free
-like function to release the root (by calling Root.release
) when it's no longer in use by the C code.
Thank you for the help. I used Ctypes.Root and Ctypes.get before the thread, but I was confused as to how to retreive the value when C passes the value back. This is my method. The add function takes a list of type x as an argument, and returns another list. The helper function takes a void ptr as an argument, and then passes an x list to the add function. I think that this portion of the code is correct, but I'm not sure how to retrive the value from C.
let add_helper a =
let x = (Root.get a :(x list)) in
Root.create (add x)
module internal ...
let () = I.internal "add_helper"(ptr void @-> returning (ptr void)) add_helper
I'm not sure where to call Root.get to retreive the value.
The root interface is quite low level, so you may find it easier to build a thin type-safe wrapper around it, and then use that. For example, here's a module that hides the void pointers and the unsafe types of the root operations:
module CList :
sig
type t
val t : t typ (* Used to describe interfaces to C *)
val alloc : int list -> t
val free : t -> unit
val get : t -> int list
val set : t -> int list -> unit
end =
struct
type t = unit ptr
let t = ptr void
let alloc = Root.create
let free = Root.release
let get = Root.get
let set = Root.set
end
Now you can use this interface to build functions that operate on C-accessible lists:
let length : CList.t -> int =
fun t -> List.length (CList.get t)
let sum : CList.t -> int =
fun t -> List.fold_left (+) 0 (CList.get t)
let empty : CList.t =
CList.alloc []
let reverse : CList.t -> CList.t =
fun t -> t |> CList.get |> List.rev |> CList.alloc
let cons : int -> CList.t -> CList.t =
fun x t -> CList.alloc (x :: (CList.get t))
and you can expose these functions to C using internal
and CList.t
:
let () = I.internal "reverse" (CList.t @-> returning CList.t) reverse
let () = I.internal "cons" (int -> CList.t @-> returning CList.t) cons
let () = I.internal "free" (CList.t -> void) CList.free
(* etc. *)
Sorry I got to this a little late. I wrote a similar interface to this, that just exposes the list as void pointers, but I kept on getting a seg fault. Then I tried this interface, but ran into a similar error. Is there something wrong with my little client program.
int main(){
int x[3] = {3, 4, 5};
int (*ptr)[3];
ptr = &x;
printf("%p\n", reverse(ptr));
free(reverse(ptr))
}
I was just trying to print the address in memory as the function returns a pointer. Even when I try to get the first element of the returned list, I get a seg fault.
int x[3] = {3, 4, 5}; int (*ptr)[3];
This snippet deals with C arrays, which have different memory representations to OCaml lists. Since the representations are different, It's not possible to treat the same value as both an OCaml list (in OCaml code), and a C array (in C code): you'll have to choose one representation or the other.
There are two options available:
exposing OCaml lists to C code.
Use the Root
approach described above.
In OCaml you'll be able to use normal programming facilities (pattern matching, etc.)
In C you'll only be able to access the value through the functions you export; you won't be able to use C array/pointer facilities.
Exposing OCaml functions that deal with C arrays to C code.
Use CArray
or ptr
or bigarray
.
In OCaml you'll need to use the functions in the ctypes
interface (CArray.get
, !@
, etc.) to manipulate values.
In C you'll be able to treat the values as arrays, pointers, etc., as your client program does.
That makes a lot more sense. I think my underlying question was can you pass a list input from C to OCaml through a void pointer. However, this seems only possible using a array on the C side and this makes first option not viable, as there is no method of giving a input for a list.
I have defined unions, and structs in my Ctypes Inverted interface with great success, but I have been having trouble in passing a list of them with the inverted stubs.
This is a basic premise of what I want to do. I have a function: let test a = [a;a;a]
let t_type = view ~read:get_t~write:set_t fin_t (this is what will be passed as a paremeter).
let() = I.internal "test" (t_type @-> returning ????) test
I have tried various methods using big_Arrays, and CArrays, but the return type still isn't what it is supposed to be. Most of the documentation I have seen has been of the regular Ctypes, and not the inverted bindings.