[ocaml-ctypes] Defines, and Structs with platform-specific fields
yallop at gmail.com
Mon Oct 20 15:10:42 BST 2014
On 20 October 2014 09:25, Jeremy Yallop <yallop at gmail.com> wrote:
> On 18 October 2014 12:49, Trevor Smith <trevorsummerssmith at gmail.com> wrote:
>> Your suggestion makes sense. If I were to do that -- any suggestions of how
>> to deal with freeing that memory? Ideally, without adding a lifecycle "free"
>> call to the user library. My thoughts would be to store the cstruct
>> reference (malloced by C) in a ref in OCaml, then attach a finalizer to the
>> OCaml ref that would call the corresponding C free.
> That approach should work, I think.
> Another possibility to allocate the struct using Ctypes.allocate or
Yet another possibility: you can avoid the need to write C altogether
by defining the public interface as a module type, defining the
platform-specific struct definitions as implementations, and using
first-class modules (or the build system, if you prefer) to pick an
appropriate definition for the platform.
For example, you might define the public interface of the uv_loop_s
structure as follows:
module type UV_LOOP =
val t : t structure typ
(* Define the public fields of the struct here *)
val data : (unit ptr, t structure) field
val active_handles : (uint, t structure) field
(* ... other public fields ... *)
This exposes the fact that the underlying type is a structure, and
that data, active_handles etc. are fields, so you can use the various
ctypes functions that deal with structs (make, getf, setf, etc.).
You can then give a platform-specific definition of the struct that
matches the UV_LOOP interface, and includes (but does not expose) the
module Uv_loop_windows : Uv_loop =
let t = structure "uv_loop_s"
let data = field t "data" (ptr void)
let active_handles = field t "active_handles" uint
(* ... other public and private fields ... *)
let time = field t "time" uint64_t
let () = seal t
Finally, first-class modules make it possible to pick an appropriate
implementation for the platform:
module Uv_loop =
(val if Sys.os_type = "win32"
then (module Uv_loop_windows : UV_LOOP)
else if Sys.os_type = "unix"
then (module Uv_loop_unix : UV_LOOP)
else failwith "Unsupported platform")
If you're not keen on first-class modules, an alternative approach is
to simply use an interface file uv.mli and an implementation file
uv.ml which is selected from various platform-specific alternatives
(uv_windows.ml, uv_unix.ml etc.) by the build system.
More information about the Ctypes