用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就可以了。

 

完。

posted @ 2017-03-23 14:37  摩斯电码  阅读(1547)  评论(0编辑  收藏  举报