用C扩展Python

参考

python扩展实现方法--python与c混和编程

编写Python扩展(Extending Python with C or C++)

https://docs.python.org/2.7/extending/embedding.html

环境

主机: ubuntu14.04 64bit

开发板: qemu + aarch64 (参考: http://www.cnblogs.com/pengdonglin137/p/6442583.html

工具链: aarch64-linux-gnu-gcc  (gcc version 4.9.1 20140529)

Python版本: Python-2.7.13

概述

上面参考列表中的文章已经说的很全了,这里仅作一些补充。分为三个:

1、交叉编译扩展模块到aarch64上面

2、编译扩展模块到Qemu模拟的x86_64上面

3、编译扩展模块到PC(x86_64)上面

采用的测试模块是Extend_wrap.c,这个在python扩展实现方法--python与c混和编程中有说明,源码如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <Python.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 void initExtest() {
74     Py_InitModule("Extest", ExtestMethods);
75 }
76
77 int main() {
78     char s[BUFSIZE];
79     printf("4! == %d\n", fac(4));
80     printf("8! == %d\n", fac(8));
81     printf("12! == %d\n", fac(12));
82     strcpy(s, "abcdef");
83     printf("reversing ‘abcdef‘, we get ‘%s‘\n", reverse(s));
84     strcpy(s, "madam");
85     printf("reversing ‘madam‘, we get ‘%s‘\n", reverse(s));
86     return 0;
87 }

关于这段代码的解释,请参考python扩展实现方法--python与c混和编程

正文

1、交叉编译扩展模块到aarch64上面

这里介绍两种方法:

第一种: 将这个文件拷贝到Python2.7.3的Modules目录下面编译

拷贝:

    cp Extest_wrap.c ../../Python-2.7.13/Modules/

修改Python-2.7.13/setup.py,添加模块:

 1 diff --git a/setup.py b/setup.py
 2 index 81355c7..5083c3d 100644
 3 --- a/setup.py
 4 +++ b/setup.py
 5 @@ -1743,6 +1743,7 @@ class PyBuildExt(build_ext):
 6                                       ‘-framework‘, ‘Carbon‘]) )
 7
 8
 9 +        exts.append(Extension(‘Extest‘, [‘Extest_wrap.c‘]))
10          self.extensions.extend(exts)
11
12          # Call the method for detecting whether _tkinter can be compiled

然后执行aarch64/mk2_make.sh,可以看到build/lib.linux2-aarch64-2.7/下面已经有Extest.so了:

1 $ls build/lib.linux2-aarch64-2.7/Extest.so -l
2 -rwxrwxr-x 1 pengdonglin pengdonglin 22121 Mar 22 14:47 build/lib.linux2-aarch64-2.7/Extest.so*

然后执行aarch64/mk3_install.sh,就会将Extest.so安装到lib/python2.7/lib-dynload/下面。

最后重新制作ramdisk文件,重启板子,测试Extest.so能否使用:

 1 [[email protected] root]# python
 2 Python 2.7.13 (default, Mar 22 2017, 10:39:43)
 3 [GCC 4.9.1 20140529 (prerelease)] on linux2
 4 Type "help", "copyright", "credits" or "license" for more information.
 5 >>> import Extest
 6 >>> Extest.fac(4)
 7 24
 8 >>> Extest.reverse("abc")
 9 ‘cba‘
10 >>> Extest.doppel("abc")
11 (‘abc‘, ‘cba‘)
12 >>> 

第二种: 手动编译

我们需要指定编译用的库以及头文件的搜索路径即可,下面是编译命令:

 1 #!/bin/bash
 2 export PATH=/home/pengdonglin/src/qemu/aarch64/gcc-linaro-aarch64-linux-gnu-4.9-2014.07_linux/bin:$PATH
 3
 4 CFLAGS="-I/home/pengdonglin/src/qemu/python_cross_compile/Python2/aarch64/include/python2.7 -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes"
 5
 6 LDFLAGS="-L/home/pengdonglin/src/qemu/python_cross_compile/Python2/aarch64/lib -lpython2.7 -lpthread -ldl -lutil -lm -Xlinker -export-dynamic"
 7
 8 aarch64-linux-gnu-gcc -c ../Extest_wrap.c ${CFLAGS} -o Extest.o
 9
10 aarch64-linux-gnu-gcc --shared Extest.o ${LDFLAGS} -o Extest.so

其中CFLAGS和LDFLAGS的值可以用下面的命令获得

1 $/usr/local/bin/python2-config --cflags
2 -I/usr/local/include/python2.7 -I/usr/local/include/python2.7 -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
3
4 $/usr/local/bin/python2-config --ldflags
5 -L/usr/local/lib/python2.7/config -lpython2.7 -lpthread -ldl -lutil -lm -Xlinker -export-dynamic

然后编译,就会在当前目录下面生成一个Extest.so,然后拷贝到板子的/usr/lib/python2.7/site-packages/下面,这个目录下存放的是一些第三方的扩展模块,而/usr/lib/python2.7/lib-dynload/存放的一般是内建模块。

2、编译扩展模块到Qemu模拟的x86_64上面

这里也有三种方法:

第一种:将Extend_wrap.c拷贝到Python源码的Modules目录下,这个前面说过,不再重复

第二种:手动编译,编译命令如下

1 #!/bin/bash
2 CFLAGS="-I/home/pengdonglin/src/qemu/python_cross_compile/Python2/x86_64/include/python2.7 -fPIC"
3
4 LDFLAGS="-L/home/pengdonglin/src/qemu/python_cross_compile/Python2/x86_64/lib -fPIC"
5
6 gcc -c ../Extest_wrap.c ${CFLAGS} -o Extest.o
7
8 gcc --shared Extest.o ${LDFLAGS} -o Extest.so

编译完成后,将Extest.so拷贝到板子上面的相应目录下即可(如/usr/lib/python2.7/site-packages)

第三种:手动编写setup.py

setup.py:

1 #!/usr/bin/env python
2
3 from distutils.core import setup, Extension
4
5 MOD = ‘Extest_x86_64‘
6 setup(name=MOD, ext_modules=[Extension(MOD, sources=[‘Extest_wrap.c‘])])

这里模块名是Extest_x86_64,同时需要注意的是需要将setup.py跟Extest_wrap.c放到同一个目录下面。

编译:

/home/pengdonglin/src/qemu/python_cross_compile/Python2/x86_64/bin/python ./setup.py build

从log看执行的其实就是下面两条命令:

gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/pengdonglin/src/qemu/python_cross_compile/Python2/x86_64/include/python2.7 -c Extest_wrap.c -o build/temp.linux-x86_64-2.7/Extest_wrap.o

creating build/lib.linux-x86_64-2.7
gcc -pthread -shared build/temp.linux-x86_64-2.7/Extest_wrap.o -o build/lib.linux-x86_64-2.7/Extest_x86_64.so

安装:

/home/pengdonglin/src/qemu/python_cross_compile/Python2/x86_64/bin/python ./setup.py  install

从log看,Extest_x86_64.so会被安装到/home/pengdonglin/src/qemu/python_cross_compile/Python2/x86_64/lib/python2.7/site-packages下面

1 running install
2 running build
3 running build_ext
4 running install_lib
5 copying build/lib.linux-x86_64-2.7/Extest_x86_64.so -> /home/pengdonglin/src/qemu/python_cross_compile/Python2/x86_64/lib/python2.7/site-packages
6 running install_egg_info
7 Writing /home/pengdonglin/src/qemu/python_cross_compile/Python2/x86_64/lib/python2.7/site-packages/Extest_x86_64-0.0.0-py2.7.egg-info

然后从新制作ramdisk就可以了

3、编译扩展模块到PC(x86_64)上面

在操作之前PC上面应该用Python源码编译安装一次,方法很简单:

#!/bin/bash
../Python-2.7.13/configure
make -j8
sudo make install

默认会被安装到/usr/local下面

方法一: 将Extend_wrap.c拷贝到Python源码的Modules目录下,这个前面说过,不再重复

方法二: 手动编译,编译命令如下

1 #!/bin/bash
2 CFLAGS="-I/usr/local/include/python2.7 -fPIC"
3 LDFLAGS="-L/usr/local/lib -fPIC"
4 gcc -c ../Extest_wrap.c ${CFLAGS} -o Extest.o
5 gcc --shared Extest.o ${LDFLAGS} -o Extest.so

将生成的Extest.so拷贝到/usr/local/lib/python2.7/site-packages/即可

测试:

1 $sudo cp Extest.so /usr/local/lib/python2.7/site-packages/
2 $/usr/local/bin/python
3 Python 2.7.13 (default, Mar 22 2017, 13:18:43)
4 [GCC 4.8.4] on linux2
5 Type "help", "copyright", "credits" or "license" for more information.
6 >>> import Extest
7 >>> Extest.reverse("peng")
8 ‘gnep‘

方法三: 编写setup.py

setup.py:

1 $cat setup.py
2 #!/usr/bin/env python
3 from distutils.core import setup, Extension
4 MOD = ‘Extest‘
5 setup(name=MOD, ext_modules=[Extension(MOD, sources=[‘Extest_wrap.c‘])])

编译:

/usr/local/bin/python ./setup.py build

从log看,执行的是下面的命令:

1 running build
2 running build_ext
3 building ‘Extest‘ extension
4 creating build
5 creating build/temp.linux-x86_64-2.7
6 gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/usr/local/include/python2.7 -c Extest_wrap.c -o build/temp.linux-x86_64-2.7/Extest_wrap.o
7 gcc -pthread -shared build/temp.linux-x86_64-2.7/Extest_wrap.o -o build/lib.linux-x86_64-2.7/Extest.so

安装:

sudo /usr/local/bin/python ./setup.py install

从log看,Extest.so被安装到了/usr/local/lib/python2.7/site-packages下面

1 running install
2 running build
3 running build_ext
4 running install_lib
5 copying build/lib.linux-x86_64-2.7/Extest.so -> /usr/local/lib/python2.7/site-packages
6 running install_egg_info
7 Removing /usr/local/lib/python2.7/site-packages/Extest-0.0.0-py2.7.egg-info
8 Writing /usr/local/lib/python2.7/site-packages/Extest-0.0.0-py2.7.egg-info

时间: 2024-08-08 09:41:54

用C扩展Python的相关文章

22 扩展Python - 《Python 核心编程》

?? 引言/动机 ?? 扩展 Python ?? 创建应用程序代码 ?? 用样板包装你的代码 ?? 编译 ?? 导入并测试 ?? 引用计数 ?? 线程和 GIL ?? 相关话题 22.1 介绍/动机 什么是扩展 一般来说,所有能被整合或导入到其它python 脚本的代码,都可以被称为扩展.您可以用纯 Python 来写扩展,也可以用C 和C++之类的编译型的语言来写扩展(或者也可以用Java 给Jython 写 扩展,也可以用C#或Visual Basic.NET 给IronPython 写扩展

使用c/c++扩展python

用python脚本写应用比较方便,但有时候由于种种原因需要扩展python(比如给程序提供python接口等). 之前一直想整理下,今天终于坐下来把这件事情给做了,这里记录下,也方便我以后查阅. 说明: 测试环境中操作系统为CentOS6.5_x64,python版本为2.6 直接调用动态库 1.编写模块动态库文代码 这里以求最大数为示例 代码(callTest1.cpp)如下: extern "C" { int Max(int i1,int i2) { return (i1>i

初用C/C++扩展Python,提高性能

前段时间写了两篇文章介绍如何提高Python的运行效率,一篇是从python语言本身的角度去介绍的,另一篇是从解释器角度(利用PyPy),有兴趣的可以找着看看.从另外一个角度来介绍如何提高python运行效率,那就是利用c/c++来扩展python提高性能.我们知道python官方网站上下载的python解释器源码是用c语言编写的,所以,也可以利用c/c++来扩展它,以获得较优的执行性能.Python提供了API接口,是我们很方便的能进行扩展,所有这些API都包含在Python.h的头文件里,在

使用C++扩展Python的功能 转自:http://blog.csdn.net/magictong/article/details/8897568#comments

使用C++扩展Python的功能 环境 VS2005Python2.5.4 Windows7(32位) 简介 长话短说,这里说的扩展Python功能与直接用其它语言写一个动态链接库,然后让Python来调用有点不一样(虽然本质是一样的).而是指使用Python本身提供的API,使用C++来对Python进行功能性扩展,可以这样理解,使用更高效的语言实现一些算法计算等等需要更高执行效率的核心(或者需要与系统进行密切交互的)模块,然后让Python像调用内建标准库的方式来调用这些模块,听起来是不是很

python学习(十七) 扩展python

c, c++, java比python快几个数量级. 17.1 考虑哪个更重要 开发速度还是运行速度更重要. 17.2 非常简单的途径:Jython和IronPython Jython可以直接访问JAVA标准库. IronPython中可以直接访问C#标准库. 17.3 编写C语言扩展 扩展Python通常就是扩展CPython,是用c语言实现的标准Python版本. 17.3.1 SWIG swig是简单包装和接口生成器的缩写,是一个能用于几种语言的工具.一方面,可以通过它使用c语言或者C++

扩展Python模块系列(一)----开发环境配置

本系列将介绍如何用C/C++扩展Python模块,使用C语言编写Python模块,添加到Python中作为一个built-in模块.Python与C之间的交互目前有几种方案: 1. 原生的Python C/C++ API, 官网有非常详细的文档说明 2. boost python,一个C++的编程框架,对官方API进行了封装,可以方便的用C++扩展Python模块,省去了很多诸如引用计数的烦恼. http://www.boost.org/doc/libs/1_64_0/libs/python/d

[Python自动化]使用C来扩展Python

一.需求背景 Python 几乎能解决你所遇到的所有问题,但 Python 常被人提及的问题就是速度问题,这时如果想提升 Python 的速度,基本都会使用 C/C++ 来扩展 Python 接口,这种方法仅仅是提升 Python 速度的诸多方法中的一种而已. 同时,对于一些使用 Python 来解决的问题比较棘手时,也可以考虑使用 C/C++ 来扩展 Python 接口,这样在调用的时候,就会减少一些 Python 带来的麻烦. 基于不同的平台,使用 C/C++ 扩展 Python 接口时,产

扩展Python模块系列(五)----异常和错误处理

在上一节中,讨论了在用C语言扩展Python模块时,应该如何处理无处不在的引用计数问题.重点关注的是在实现一个C Python的函数时,对于一个PyObject对象,何时调用Py_INCREF和Py_DECREF.在编写C语言代码时,需要了解Python提供的C/C++ API的实现细节,特别是有的API内部实现会调用Py_INCREF,这时自己编写的函数可能需要调用Py_DECREF,而有的API内部实现只是borrowed reference,此时一般不应该调用Py_DECREF. 本节讨论

【转】用C语言扩展Python的功能

原作者:肖文鹏 ([email protected]),原文地址:http://www.ibm.com/developerworks/cn/linux/l-pythc/ Pyton和C分别有着各自的优缺点,用Python开发程序速度快,可靠性高,并且有许多现成模块可供使用,但执行速度相对较慢:C语言则正好相反,其执行速度快,但开发效率低.为了充分利用两种语言各自的优点,比较好的做法是用Python开发整个软件框架,而用C语言实现其关键模块.本文介绍如何利用C语言来扩展Python的功能,并辅以具

利用boost.python 通过c++语言来扩展python (python.boost)

python语言的优良性就不多说了,我想提下如何使用boost.python,通过boost.python既可以将python转移到C++上,通过Python库,也可以通过C++来扩展python,下面主要介绍使用boost.python来扩展python的功能,第一次用boost.python,倒腾了半天才搞定: 首先列出我的测试环境: 我用的是VS2010,python2.7,我用VS2010创建了一个windows DLL的项目,项目名称为pylib,在DLL main中加入如下代码: /