How to use DEFCFUN with a pointer to a foreign C function?

191 views Asked by At

I am using CFFI to interact with a library that uses GLib. The g_list_free_full() function in GLib has the signature:

void
g_list_free_full (GList *list,
                  GDestroyNotify free_func);

I will need to call this function from Lisp because I am working with some functions in which I need to create GList objects, so I also need to free them afterwards. In C, I would do it like this (see also this answer):

g_list_free_full(res, g_free);

So far my Lisp bindings look like this:

(asdf:load-system :cffi)

(defpackage :test-glib-bindings
  (:use :common-lisp :cffi))

(in-package :test-glib-bindings)

(define-foreign-library libglib
  (:unix (:or "libglib-2.0.so.0" "libglib-2.0.so")))

(use-foreign-library libglib)

(defctype gint :int)
(defctype gboolean :boolean)
(defctype gpointer :pointer)

(defcfun "g_free" :void
  (mem gpointer))

(defcfun "g_list_free_full" :void
  (lst gpointer)
  (fun :pointer))

But I'm not sure if my defcfun signature is correct for g_list_free_full(), and I'm not sure how to call it correctly from Lisp. My naive guess is to write:

(g-list-free-full my-glist (get-callback 'g-free))

but it's hard to tell if this is the right way (or best way) to do things. I'm also not an experienced C programmer, and I don't know if this will technically work but cause some kind of other problem in the future.

1

There are 1 answers

2
coredump On

I am not sure if get-callback is defined for functions not declared with defcallback. This is not tested, but you probably only need to resolve the "g_free" symbol in the library to its pointer, and pass this value as an argument.

You can call fs-pointer-or-lose or foreign-symbol-ptr to get the pointer to the native g_free function; instead of calling (get-callback 'g-free), you write:

(fs-pointer-or-loose "g_free")

Alternatively, at the cost of doing a trip back to Lisp, you can use defcallback and callback. For that, you need define a Lisp free function as a callback, and have it call the native function.

(defcfun (g-free "g_free") :void (mem gpointer))

(defcallback free :void ((mem gpointer))
  (g-free mem))

Then you would pass the pointer to the callback with callback.

(g-list-free-full my-glist (callback free))