Created
October 19, 2015 22:28
-
-
Save insertinterestingnamehere/df7894b414a94a4456c5 to your computer and use it in GitHub Desktop.
This shows how to wrap a C++ function in a capsule within Cython, how to call a function pointer wrapped in a capsule object, how to export that function as a part of the modules C API, and how to call that function from outside the module using ctypes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cdef double cymul(double, double) nogil |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# distutils: language = c++ | |
from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer | |
# Could just include from the cpp file, but that's less standard, | |
# so I'll use a header here. | |
cdef extern from "thing.hpp": | |
cdef double mul(double a, double b) nogil | |
# Wrap the function in a capsule | |
capsule_mul = PyCapsule_New(<void*>&mul, "mod.capsule_mul", NULL) | |
# Get the function pointer back out of the capsule | |
cdef double (*mul_ptr)(double, double) nogil | |
mul_ptr = <double (*)(double, double) nogil> PyCapsule_GetPointer(capsule_mul, "mod.capsule_mul") | |
# Wrap the function pointer inside another function that is exposed via a capsule to other Cython modules. | |
cdef double cymul(double a, double b) nogil: | |
return mul_ptr(a, b) | |
# Export a Python API built off of the Cython exported function. | |
def pymul(double a, double b): | |
return cymul(a, b) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rm -rf build mod.cpp mod.pyd mod.so | |
python setup.py build_ext --inplace | |
python test.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from distutils.core import setup | |
from distutils.extension import Extension | |
from Cython.Build import cythonize | |
# Call cythonize in advance so a single module can be compiled from a single Cython | |
# file along with other C++ files. | |
cythonize('*.pyx', language='c++') | |
setup(ext_modules=[Extension('mod', sources=['mod.cpp', 'thing.cpp'], language='c++')]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ctypes as ct | |
ct.pythonapi.PyCapsule_GetPointer.restype = ct.c_void_p | |
ct.pythonapi.PyCapsule_GetPointer.argtypes = [ct.py_object, ct.c_char_p] | |
ptr_type = ct.CFUNCTYPE(ct.c_double, ct.c_double, ct.c_double) | |
import mod | |
# Get the function pointer from the capsule "capsule_mul" | |
handle = ptr_type(ct.pythonapi.PyCapsule_GetPointer(mod.capsule_mul, "mod.capsule_mul")) | |
# Get the function pointer from the Cython wrapper around the function pointer. | |
ct.pythonapi.PyCapsule_GetPointer.restype = ct.c_void_p | |
ct.pythonapi.PyCapsule_GetPointer.argtypes = [ct.py_object, ct.c_char_p] | |
ct.pythonapi.PyCapsule_GetName.restype = ct.c_char_p | |
ct.pythonapi.PyCapsule_GetName.argtypes = [ct.py_object] | |
other_handle = ptr_type( | |
ct.pythonapi.PyCapsule_GetPointer( | |
mod.__pyx_capi__['cymul'], | |
ct.pythonapi.PyCapsule_GetName( | |
mod.__pyx_capi__['cymul']))) | |
# Call all three exposed versions of the function. | |
print handle(ct.c_double(1), ct.c_double(2)) | |
print other_handle(ct.c_double(1), ct.c_double(2)) | |
print mod.pymul(1, 2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
double mul(double a, double b) { return a * b; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
double mul(double, double); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment