I'm using ctypesgen and ctypesgen_to_pxd to generate both a ctypes wrapper for a given native library as well as a pxd containing those types.
I'm able to use the generated ctypes wrapper to call into native code from Python very easily. What I can't figure out how to do is to return a function pointer of a Python callback back via a hand-written pyx (see below) to my native library, which can then call that function pointer to execute some Python code.
Here is a complete and runnable sample on Github that shows my problem. You can build it using the provided build-and-run.sh
or use VS Code remote containers to open the workspace. This latter method also allows you to debug and recompile as opposed to using the shell script = docker build + run.
The contents of cythoncallbacks.pyx.in is below for quick reference
# cython: language_level=3
import sys
sys.path.insert(0, '')
from ctypes import *
from nativelib cimport *
import nativelib as n
@CFUNCTYPE(UNCHECKED(n.NativeResult), n.NativeLibHdl)
def python_cfunctype_callback(libHdl) -> n.NativeResult:
print("Do stuff in a CFUNCTYPE Python function here...")
return n.NativeResult(n.RESULT_OK)
def python_regular_callback(libHdl: n.NativeLibHdl) -> n.NativeResult:
print("Do stuff in a regular Python callback here...")
return n.NativeResult(n.RESULT_OK)
cdef public NativeResult cythoncallbacks_getcallbacks(NativeLibHdl libHdl, CallbackParams params, NativeCallbacksHdl callbacksHdl):
# How do I call python_cfunctype_callback or python_regular_callback from here?
# Both ways below won't compile
###################################################
# Errors out with
# Cannot convert Python object to CallbackFunc* or
# From https://stackoverflow.com/a/33485103/802203
# callbacksHdl.callback = python_cfunctype_callback
###################################################
# Errors out with
# Storing unsafe C derivative of temporary Python reference
# from https://stackoverflow.com/questions/2038839/python-ctypes-addressof-cfunctype
# callbacktype = CFUNCTYPE(UNCHECKED(n.NativeResult), n.NativeLibHdl)
# callbacksHdl.callback = callbacktype(python_cfunctype_callback)
####################################################################################
return NativeResult(RESULT_NOT_IMPLEMENTED)
The sections above within the ######################
lines is what I'm trying to figure out. Ideally I'd prefer to use python_regular_callback
if possible so I can load the appropriate module methods dynamically like I would with a dlopen
and dlsym
.
- The auto-generated ctypes wrapper is here - nativelib.py
- The auto-generated pxd is here - nativelib.pxd
Thanks in advance, always glad to clarify or provide more information.