用C扩展Python3
官方文档:
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 PyMethodDef 66 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 ExtestMethods 79 }; 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.o 11 $(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 *.so 16 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 python3 2 3 from distutils.core import setup, Extension 4 5 MOD = 'Extest' 6 setup(name=MOD, ext_modules=[Extension(MOD, sources=['Extest.c'])])
编译
1 $/usr/local/bin/python3 ./setup.py build 2 running build 3 running build_ext 4 building 'Extest' extension 5 creating build 6 creating build/temp.linux-x86_64-3.6 7 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.o 8 creating build/lib.linux-x86_64-3.6 9 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 install 2 [sudo] password for pengdonglin: 3 running install 4 running build 5 running build_ext 6 running install_lib 7 copying build/lib.linux-x86_64-3.6/Extest.cpython-36m-x86_64-linux-gnu.so -> /usr/local/lib/python3.6/site-packages 8 running install_egg_info 9 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 24 10 >>> Extest.reverse("pengdonglin") 11 'nilgnodgnep' 12 >>> Extest.doppel("pengdonglin") 13 ('pengdonglin', 'nilgnodgnep') 14 >>>
可以在第7行看到加载的Extest.so的路径,而且我们只需要import Extest就可以了。
完。
本文来自博客园,作者:摩斯电码,未经同意,禁止转载