OCaml Ctypes and pointer to type allocation

I am trying to call C code from OCaml where I need to cast an assigned pointer to my type yaml_parser_t

. But I'm not sure how I should assign a valid pointer. Below is a sample code.

Ideally, I would not want to provide a specific implementation for yaml_parser_t

, since I don't need to check its internals, just pass it to various functions. I originally followed the time_t example from Real World OCaml , but they seem to use a function time

to highlight which I don't have here.

Sorry for the confusing explanation.

open PosixTypes;;
open Ctypes;;
open Foreign;;

type yaml_parser_t = unit;;
let yaml_parser_t : yaml_parser_t typ = void;;

(* To get it working in utop, specify the name of the library *)
let libyaml = Dl.(dlopen ~filename:"libyaml.dylib" ~flags:[RTLD_NOW]);;

let init = foreign "yaml_parser_initialize" (ptr yaml_parser_t @-> returning int);;

let make =
    let p_ptr = allocate yaml_parser_t (from_voidp yaml_parser) in
    let _ = init p_ptr in
    p_ptr;;

      

+3


source to share


1 answer


To make something stand out, you need to know its size. In the library, the libyaml

type is yaml_parser_t

not opaque, so the most correct way to work with such a type would be to declare it in ctypes as a struct and describe all its fields. In this case, you can simply use a function allocate

to create the value. But I will understand you if you refuse to do it. The structure yaml_parser_t

is huge and life is too short. Since there is no way to know the size of the structure at runtime, you either need to write the function with stub or just write it in your library. The latter is not as bad as one might think, since the size should only change when major versions change, since it is yaml_parser_t

explicitly made opaque and considered part of the interface.

Highlighting data for abstract values

There are two functions in ctypes that allow you to allocate memory, namely allocate

and allocate_n

. The first requires an instance of the allocated value. Since our type is abstract, we will use the latter since it does not require a value from us.

First, we need to define an abstract type. We only need to provide three values: name, size and alignment. The name is easy, it can be an arbitrary string. The size and alignment are only known for sure for the C compiler. The easiest way is to write a small program that prints them using time sizeof

and instructions __alignof__

. And then copy the file into your code ml

. If you find this solution messy, you can write two primitive c functions that return these values ​​at runtime. So, let's say you've restored these values, then we can now create a type for yaml_parser_t

:

let size = 100
let alignment = 0

let yaml_parser_t : unit abstract typ =
  abstract ~name:"yaml_parser_t" ~size ~alignment

      

Now you can use yaml_parser_t

to allocate memory:



let allocate_yaml_parser () : unit abstract ptr =
  allocate_n yaml_parser_t ~count:1

      

And then you can try to highlight it:

# let p = allocate_yaml_parser ();;
val p : unit Ctypes.abstract Ctypes.ptr = (yaml_parser_t*) 0x10156d0

      

Then you can cast it to empty or some other type and pass it to your stubs.

PS The interface is libyaml

rather strange, that is, the root of the problem. The type yaml_parser_t

must be opaque and given a function that creates it. But unfortunately, we have what we have.

+4


source







All Articles