python 从扩展模块中定义和导出C的API

C语言定义函数库API

  • C语言定义函数头源代码,sample.h
/*
 * sample.h
 *
 *  Created on: 2022年12月29日
 *      Author: xzlAwin
 */
extern int gcd(int x, int y);
extern int in_mandel(double x0, double y0, int n);
extern int divide(int a, int b, int *remainder);
extern double avg(double *a, int n);

typedef struct Point {
	double x,y;
} Point;

extern double distance(Point *p1, Point *p2);
  • C语言实现定义函数源代码,sample.c
/*
 * sample.c
 *
 *  Created on: 2022年12月29日
 *      Author: xzlAwin
 */

#include<math.h>

/* Compute the greatest common divisor */
int gcd(int x, int y) {
	int g = y;
	while(x > 0) {
		g = x;
		x = y % x;
		y = g;
	}
	return g;
}

/* Test if (x0,y0) is in the Mandelbrot set or not */
int in_mandel(double x0, double y0, int n) {
	double x=0,y=0,xtemp;
	while (n > 0) {
		xtemp = x*x - y*y +x0;
		y = 2*x*y + y0;
		x = xtemp;
		n -= 1;
		if(x*x + y*y > 4) return 0;
	}
	return 1;
}

/* Divide two numbers */
int divide(int a, int b, int *remainder) {
	int quot = a / b;
	*remainder = a % b;
	return quot;
}

/* Average values in an array */
double avg(double *a, int n) {
	int i;
	double total = 0.0;
	for (i = 0; i < n; i++) {
		total += a[i];
	}
	return total / n;
}

/* A C data structure */
typedef struct Point {
	double x,y;
} Point;

/* Function involving a C data structure */
double distance(Point *p1, Point *p2) {
	return hypot(p1->x - p2->x, p1->y - p2->y);
}
  • C语言暴露函数库API源代码,pysample.c
/*
 * pysample.h
 *
 *  Created on: 2022年12月30日
 *      Author: xzlAwin
 */

#include "Python.h"
#include "sample.h"
#ifdef __cplusplus
extern "C" {
#endif

/* Public API Table */
typedef struct {
	Point *(*aspoint)(PyObject *);
	PyObject *(*frompoint)(Point *, int);
} _PointAPIMethods;

#ifndef PYSAMPLE_MODULE
/* Method table in external module */
static _PointAPIMethods *_point_api = 0;

/* Import the API table from sample */
static int import_sample(void) {
	_point_api = (_PointAPIMethods *) PyCapsule_Import("sample._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
  • python编译配置,setup.py
from distutils.core import setup, Extension

setup(name="sample",
    ext_modules=[
        Extension(
            "sample",
            ["sample.c", "pysample.c"],
            include_dirs=[".."]
        )
    ]
)
  • python命令行,编译函数库,编译成功生成 编译成功生成 sample.cp37-win_amd64.pyd
python3 setup.py build_ext --inplace

扩展模块中的定义

  • 扩展模块头源代码,pysample.h
/*
 * pysample.h
 *
 *  Created on: 2022年12月30日
 *      Author: xzlAwin
 */

#include "Python.h"
#include "sample.h"
#ifdef __cplusplus
extern "C" {
#endif

/* Public API Table */
typedef struct {
	Point *(*aspoint)(PyObject *);
	PyObject *(*frompoint)(Point *, int);
} _PointAPIMethods;

#ifndef PYSAMPLE_MODULE
/* Method table in external module */
static _PointAPIMethods *_point_api = 0;

/* Import the API table from sample */
static int import_sample(void) {
	_point_api = (_PointAPIMethods *) PyCapsule_Import("sample._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
  • 扩展模块源代码,ptexample.c
/*
 * ptexample.c
 *
 *  Created on: 2022年12月30日
 *      Author: xzlAwin
 */

/* Include the header associated with the other module */
#include "pysample.h"

/* An extension function that uses the exported API */
static PyObject *print_point(PyObject *self, PyObject *args) {
	PyObject *obj;
	Point *p;
	if (!PyArg_ParseTuple(args,"O", &obj)) {
		return NULL;
	}

	/* Note: This is defined in a different module */
	p = PyPoint_AsPoint(obj);
	if (!p) {
		return NULL;
	}
	printf("%f %f\n", p->x, p->y);
	return Py_BuildValue("");
}

static PyMethodDef PtExampleMethods[] = {
	{"print_point", print_point, METH_VARARGS, "output a point"},
	{ NULL, NULL, 0, NULL}
};

static struct PyModuleDef ptexamplemodule = {
	PyModuleDef_HEAD_INIT,
	/* name of module */
	"ptexample",
	/* Doc string (may be NULL) */
	"A module that imports an API",
	/* Size of per-interpreter state or -1 */
	-1,
	/* Method table */
	PtExampleMethods
};

/* Module initialization function */
PyMODINIT_FUNC
PyInit_ptexample(void) {
	PyObject *m;

	m = PyModule_Create(&ptexamplemodule);
	if (m == NULL)
		return NULL;

	/* Import sample, loading its API functions */
	if (!import_sample()) {
		return NULL;
	}
	return m;
}
  • python编译配置,ptsetup.py
from distutils.core import setup, Extension

setup(name="sample",
    ext_modules=[
        Extension(
            "ptexample",
            ["ptexample.c"],
            include_dirs=["."]
        )
    ]
)
  • python命令行,编译函数库,编译成功生成 编译成功生成 ptexample.cp37-win_amd64.pyd
python3 ptsetup.py build_ext --inplace

测试

  • python调用库和扩展模块,main.py
import sample
import ptexample

p1 = sample.Point(2, 3)
print(p1)
ptexample.print_point(p1)
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐