Suppose given a C extension module that internally defines a variety of useful functions that can be exported as a public C API for use elsewhere. Now if we want to use these functions inside other extension modules. Then, it is important to know how to link them together but doing it with the C compiler/linker seems excessively complicated.
Code #1 : [C code] Point objects including some utility functions
# Destructor function for points static void del_Point(PyObject *obj) { free (PyCapsule_GetPointer(obj, "Point" )); } static PyObject *PyPoint_FromPoint(Point *p, int must_free) { return PyCapsule_New(p, "Point" , must_free ? del_Point : NULL); } # Utility functions static Point *PyPoint_AsPoint(PyObject *obj) { return (Point *) PyCapsule_GetPointer(obj, "Point" ); } |
Now, the issue to deal with is how to handle the exportation of the PyPoint_AsPoint()
and PyPoint_FromPoint()
functions as an API that can be used by and can link to other extension modules. (For example – any other extensions also want to use the wrapped Point objects).
Code #2 : Introducing a new header file called Pythonsample.h
for the work
extension.
//pythonsample.h #include "Python.h" #include "work.h" #ifdef __cplusplus extern "C" { #endif // Public API Table typedef struct { Point *(*aspoint)(PyObject *); PyObject *(*frompoint)(Point *, int ); } _PointAPIMethods; #ifndef PYTHONSAMPLE_MODULE /* Method table in external module */ static _PointAPIMethods *_point_api = 0; |
Code #3 : Import the API table from “work”
static int import_sample( void ) { _point_api = (_PointAPIMethods *) PyCapsule_Import( "work._point_api" , 0); return (_point_api != NULL) ? 1 : 0; } /* Macros to implement the programming interface */ #define PyPoint_AsPoint(obj) (_point_api->aspoint)(obj) #define PyPoint_FromPoint(obj) (_point_api->frompoint)(obj) #endif #ifdef __cplusplus } #endif |
_PointAPIMethods table of function pointers is the most important feature as it will be initialized in the exporting module and found by importing modules. The code below shows how to change the original extension module to populate the table and export it.
Code #4 : Destructor and Utility Function
/ / pythonsample.c # include "Python.h" # define PYTHONSAMPLE_MODULE # include "pythonsample.h" / / Destructor function for points static void del_Point(PyObject * obj) { printf( "Deleting point\n" ); free(PyCapsule_GetPointer(obj, "Point" )); } / / Utility functions static Point * PyPoint_AsPoint(PyObject * obj) { return (Point * ) PyCapsule_GetPointer(obj, "Point" ); } static PyObject * PyPoint_FromPoint(Point * p, int free) { return PyCapsule_New(p, "Point" , free ? del_Point : NULL); } static _PointAPIMethods _point_api = { PyPoint_AsPoint, PyPoint_FromPoint }; |
Code #5 : Module function
// Module initialization function PyMODINIT_FUNC PyInit_sample( void ) { PyObject *m; PyObject *py_point_api; m = PyModule_Create(&samplemodule); if (m == NULL) return NULL; // Add the Point C API functions py_point_api = PyCapsule_New(( void *) &_point_api, "work._point_api" , NULL); if (py_point_api) { PyModule_AddObject(m, "_point_api" , py_point_api); } return m; } |