徐高翔的个人网站

使用Cython编译动态链接库

2018-08-29

软硬件环境

  • ubuntu 18.04 64bit
  • anaconda with python 3.6
  • cython 0.27.3

cython简介

Cython是让Python脚本支持C语言扩展的编译器,是python的超集,Cython能够将PythonC混合编码的.pyx脚本转换为C代码,主要用于优化Python脚本性能或Python调用C函数库。由于Python固有的性能差的问题,用C扩展Python成为提高Python性能常用方法。本文主要是介绍如何使用cythonpython代码编译成C语言中的动态链接库,也就是常说的so

cython安装

使用pip进行安装

1
pip install cython

准备python模块

1
2
3
4
cd /home/xugaoxiang/anaconda3/lib/python3.6/site-packages
mkdir djstava
cd djstava
touch __init__.py test.py

编辑 test.py 文件内容

1
2
3
4
5
def test():
'''
Just an example.
'''
print('Hello Cython.')

接下来测试下创建的模块是否可以被导入,其中的方法是否可以正常运行。这个可以用 python 或者 ipython 来进行

1
2
3
4
5
6
7
8
9
10
11
12
13
xugaoxiang@ubuntu:~/anaconda3/lib/python3.6/site-packages/djstava$ python
Python 3.6.4 |Anaconda custom (64-bit)| (default, Jan 16 2018, 18:10:19)
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import djstava.test
>>> djstava.test.test
<function test at 0x7ff35f135598>
>>> djstava.test.test()
Hello Cython.

```

### 编译成so库

cd /home/xugaoxiang/anaconda3/lib/python3.6/site-packages/djstava
cython test.py

1
生成了`test.c`文件,然后

gcc -c -fPIC -I/home/xugaoxiang/anaconda3/include/python3.6m test.c

1
生成目标文件即`.o`文件

gcc -shared test.o -o test.so

1
2
3
4
5
6
 
到此,动态库正式生成。

### 测试

这次我们用`ipython`来测试,首先进到目录`/home/xugaoxiang/anaconda3/lib/python3.6/site-packages/djstava`,将test.py文件删除,防止它形成干扰

xugaoxiang@ubuntu:~/anaconda3/lib/python3.6/site-packages/djstava$ ipython
Python 3.6.4 |Anaconda custom (64-bit)| (default, Jan 16 2018, 18:10:19)
Type ‘copyright’, ‘credits’ or ‘license’ for more information
IPython 6.2.1 – An enhanced Interactive Python. Type ‘?’ for help.

In [1]: import djstava.test

In [2]: djstava.test.test
Out[2]: <cyfunction test at 0x7f90945bbc80>

In [3]: djstava.test.test()
Hello Cython.

1
2
3
4
5
6
 
另外,`python`中如何去调用`so`库,请见之前的文章<https://xugaoxiang.com/20>

### 结合setup.py使用

如果还不了解`setup.py`的话,请移步<https://xugaoxiang.com/144>。为了跟上面的工程相冲突,我们新建一个新的目录`/home/xugaoxiang/test`,然后创建文件`test.pyx`,`pyx`文件允许`C`和`python`进行混编,它的内容如下

def test():
‘’’
Just an example.
‘’’
print(‘Hello Cython.’)

1
2

编写`setup.py`文件

from distutils.core import setup
from Cython.Build import cythonize

setup(
name=’Test pyx’,
ext_modules=cythonize(‘test.pyx’)
)

1
2

编辑完毕,开始安装

xugaoxiang@ubuntu:~/test$ python setup.py build
Compiling test.pyx because it changed.
[1/1] Cythonizing test.pyx
running build
running build_ext
building ‘test’ extension
creating build
creating build/temp.linux-x86_64-3.6
gcc -pthread -B /home/xugaoxiang/anaconda3/compiler_compat -Wl,–sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/xugaoxiang/anaconda3/include/python3.6m -c test.c -o build/temp.linux-x86_64-3.6/test.o
creating build/lib.linux-x86_64-3.6
gcc -pthread -shared -B /home/xugaoxiang/anaconda3/compiler_compat -L/home/xugaoxiang/anaconda3/lib -Wl,-rpath=/home/xugaoxiang/anaconda3/lib -Wl,–no-as-needed -Wl,–sysroot=/ build/temp.linux-x86_64-3.6/test.o -o build/lib.linux-x86_64-3.6/test.cpython-36m-x86_64-linux-gnu.so

1
2

编译后的文件目录结构如下

xugaoxiang@ubuntu:~/test$ ls -R
.:
build setup.py test.c test.pyx

./build:
lib.linux-x86_64-3.6 temp.linux-x86_64-3.6

./build/lib.linux-x86_64-3.6:
test.cpython-36m-x86_64-linux-gnu.so

./build/temp.linux-x86_64-3.6:
test.o

1
注意到,test.c文件已经生成,同时还有build下的`.o`及`.so`文件。同样的,我们用`ipython`来测试下生成的`so`文件,在当前目录下创建一个全新的文件夹,然后将上步中生成的`so`文件拷贝过来,再新建一个`__init__.py`文件,内容是

from test import *

1
2

然后开始测试

xugaoxiang@ubuntu:~/test/test$ ipython
Python 3.6.4 |Anaconda custom (64-bit)| (default, Jan 16 2018, 18:10:19)
Type ‘copyright’, ‘credits’ or ‘license’ for more information
IPython 6.2.1 – An enhanced Interactive Python. Type ‘?’ for help.

In [1]: import test

In [2]: test.test()
Hello Cython.
```

参考资料

推荐文章(由hexo文章推荐插件驱动)

使用支付宝打赏
使用微信打赏

请博主喝咖啡!