For 1) the easiest way for getting #ifdef'd symbols into OCaml is to write a C program that outputs a seperate module with the value of these symbol. You then just use this module in your bindings when you need the symbols. You can find an example of this approach here.
For 2) I'd say ctypes's string
is a little bit deceptive as it doesn't seem to act in a bidirectional fashion, that is you should only use it for const char *
or return types. In this case you need to use arrays of character and then translate it to a string (this char_array_as_string
function should be added to ctypes I think). Here's the full example, note that in future versions of ctypes the Array
module will change its name to CArray
:
(* Compile with: ocamlfind ocamlopt -package ctypes.foreign -linkpkg -cclib -lpcap \
-o test.native test.ml *)
open Ctypes;;
open Foreign;;
module Pcap : sig
val lookupdev : unit -> [ `Ok of string | `Error of string ]
end = struct
let errbuf_size = 256 (* N.B. This should not be hardcoded, see 1) above *)
let char_array_as_string a =
let len = Array.length a in
let b = Buffer.create len in
try
for i = 0 to len -1 do
let c = Array.get a i in
if c = '\x00' then raise Exit else Buffer.add_char b c
done;
Buffer.contents b
with Exit -> Buffer.contents b
let lookupdev =
foreign "pcap_lookupdev" (ptr char @-> returning string_opt)
let lookupdev () =
let err = Array.make char ~initial:'\x00' errbuf_size in
match lookupdev (Array.start err) with
| None -> `Error (char_array_as_string err)
| Some dev -> `Ok dev
end
let test () = match Pcap.lookupdev () with
| `Ok dev -> Printf.printf "dev: %s\n" dev
| `Error err -> Printf.printf "error: %s\n" err
let () = test ()