用C扩展python3

来源:互联网 发布:打印机接收数据 不打印 编辑:程序博客网 时间:2024/06/14 22:02

转载自  http://www.cnblogs.com/pengdonglin137/p/6605046.html


官方文档:

https://docs.python.org/3/extending/index.html

  • 交叉编译到aarch64上面

以交叉编译到aarch64上面为例,下面是Extest.c的实现:

复制代码
 1 #include <Python.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5  6 #define BUFSIZE 10 7  8 int fac(int n) { 9     if (n < 2)10         return 1;11     return n * fac(n - 1);12 }13 14 static PyObject * Extest_fac(PyObject *self, PyObject *args) {15     int res;//计算结果值16     int num;//参数17     PyObject* retval;//返回值18 19     //i表示需要传递进来的参数类型为整型,如果是,就赋值给num,如果不是,返回NULL;20     res = PyArg_ParseTuple(args, "i", &num);21     if (!res) {22         //包装函数返回NULL,就会在Python调用中产生一个TypeError的异常23         return NULL;24     }25     res = fac(num);26     //需要把c中计算的结果转成python对象,i代表整数对象类型。27     retval = (PyObject *)Py_BuildValue("i", res);28     return retval;29 }30 31 char *reverse(char *s) {32     register char t;33     char *p = s;34     char *q = (s + (strlen(s) - 1));35     while (p < q) {36         t = *p;37         *p++ = *q;38         *q-- = t;39     }40     return s;41 }42 43 static PyObject *44 Extest_reverse(PyObject *self, PyObject *args) {45     char *orignal;46     if (!(PyArg_ParseTuple(args, "s", &orignal))) {47         return NULL;48     }49     return (PyObject *)Py_BuildValue("s", reverse(orignal));50 }51 52 static PyObject *53 Extest_doppel(PyObject *self, PyObject *args) {54     char *orignal;55     char *reversed;56     PyObject * retval;57     if (!(PyArg_ParseTuple(args, "s", &orignal))) {58         return NULL;59     }60     retval = (PyObject *)Py_BuildValue("ss", orignal, reversed=reverse(strdup(orignal)));61     free(reversed);62     return retval;63 }64 65 static PyMethodDef66 ExtestMethods[] = {67     {"fac", Extest_fac, METH_VARARGS},68     {"doppel", Extest_doppel, METH_VARARGS},69     {"reverse", Extest_reverse, METH_VARARGS},70     {NULL, NULL},71 };72 73 static struct PyModuleDef ExtestModule = {74     PyModuleDef_HEAD_INIT,75     "Extest",76     NULL,77     -1,78     ExtestMethods79 };80 81 PyMODINIT_FUNC PyInit_Extest(void)82 {83     return PyModule_Create(&ExtestModule);84 }
复制代码

采用手动编译, Makefile如下:

复制代码
 1 CFLAGS = -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes 2 CFLAGS += -fPIC -I /home/pengdonglin/src/qemu/python_cross_compile/Python3/aarch64/include/python3.6m 3 CC = /home/pengdonglin/src/qemu/aarch64/gcc-linaro-aarch64-linux-gnu-4.9-2014.07_linux/bin/aarch64-linux-gnu-gcc 4  5 all:Extest.so 6  7 Extest.o: Extest.c 8     $(CC) $(CFLAGS) -c $^ -o $@ 9 10 Extest.so: Extest.o11     $(CC) -pthread -shared $^ -o $@12     cp $@ /home/pengdonglin/src/qemu/python_cross_compile/Python3/aarch64/lib/python3.6/site-packages/13 14 clean:15     $(RM) *.o *.so16 17 .PHONY: clean all
复制代码

执行make命令,就会在当前目录下生成一个Extest.so文件,然后将其放到板子上面的/usr/lib/python3.6/site-packages/下面即可

测试:

复制代码
 1 [root@aarch64 root]# cp /mnt/Extest.so /usr/lib/python3.6/site-packages/ 2 [root@aarch64 root]# python3 3 Python 3.6.0 (default, Mar 23 2017, 10:54:13)  4 [GCC 4.9.1 20140529 (prerelease)] on linux 5 Type "help", "copyright", "credits" or "license" for more information. 6 >>> import Extest 7 >>> Extest.fac(4) 8 24 9 >>> Extest.reverse("pengdonglin")10 'nilgnodgnep'11 >>> Extest.doppel("pengdonglin")12 ('pengdonglin', 'nilgnodgnep')
复制代码
  • 编译到x86_64上面

编写setup.py如下:

复制代码
1 #/usr/bin/env python32 3 from distutils.core import setup, Extension4 5 MOD = 'Extest'6 setup(name=MOD, ext_modules=[Extension(MOD, sources=['Extest.c'])])
复制代码

编译

复制代码
1 $/usr/local/bin/python3 ./setup.py build2 running build3 running build_ext4 building 'Extest' extension5 creating build6 creating build/temp.linux-x86_64-3.67 gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/usr/local/include/python3.6m -c Extest.c -o build/temp.linux-x86_64-3.6/Extest.o8 creating build/lib.linux-x86_64-3.69 gcc -pthread -shared build/temp.linux-x86_64-3.6/Extest.o -o build/lib.linux-x86_64-3.6/Extest.cpython-36m-x86_64-linux-gnu.so
复制代码

可以看到,在Python3上面用setup.py默认生成的so的名字是Extest.cpython-36m-x86_64-linux-gnu.so

安装

复制代码
1 $sudo /usr/local/bin/python3 ./setup.py install2 [sudo] password for pengdonglin: 3 running install4 running build5 running build_ext6 running install_lib7 copying build/lib.linux-x86_64-3.6/Extest.cpython-36m-x86_64-linux-gnu.so -> /usr/local/lib/python3.6/site-packages8 running install_egg_info9 Writing /usr/local/lib/python3.6/site-packages/Extest-0.0.0-py3.6.egg-info
复制代码

可以看到,将Extest.cpython-36m-x86_64-linux-gnu.so拷贝到了/usr/local/lib/python3.6/site-packages下面。

测试

在PC上面输入python3命令:

复制代码
 1 $python3 2 Python 3.6.0 (default, Mar 23 2017, 10:40:28)  3 [GCC 4.8.4] on linux 4 Type "help", "copyright", "credits" or "license" for more information. 5 >>> import Extest 6 >>> Extest 7 <module 'Extest' from '/usr/local/lib/python3.6/site-packages/Extest.cpython-36m-x86_64-linux-gnu.so'> 8 >>> Extest.fac(4) 9 2410 >>> Extest.reverse("pengdonglin")11 'nilgnodgnep'12 >>> Extest.doppel("pengdonglin")13 ('pengdonglin', 'nilgnodgnep')14 >>> 
复制代码

可以在第7行看到加载的Extest.so的路径,而且我们只需要import Extest就可以了。

 

完。