cython 本质上是写cython 语言,然后通过Cython 工具转化为C代码。并且转化的C代码生成的动态链接库是可以直接作为python库用的。 因为cython在生成C代码时插入了所有 扩展为python库的必须函数借口.
# 概念
cython是 Python 与 C/C++ 的中间沟通语言
cython 是Python 与 C/C++ 的合集的修改
cython 通过引用C++的头文件,获得函数的声明,后期再链接 C++ 的obj文件, 找到对应的函数实现.
eg:
cython -3 cy_file.pyx -o cy_file.c
1 cython 可以引用C源码,因此可以用来封装C/C++ 的源码。
2 cython 转化代码时, 会自己增加很多python 扩展API, 因此, 编译成so 可以作为python模块调用.
3 cython 可以利用python的易用性, 来写代码, 然后cython直接将其转化为C代码,这样形成的库,最后提升执行效率.
# 使用
1 封装C/C++ 动态链接库so, 形成一个模块, 扩展python
这是通过修改 cy_file.pyx文件,
cython 向其中 添加 #include "Python.h",
使用Python API 修改cy_file.pyx 为调用了 Python API 的 C 源文件
这样的 cy_file.c 就编译 链接 后的 .so 这样得到的 动态链接库.so 就是正常的so库, 同时也可以用作python的扩展模块
2 将Python 处理为C/C++语言
cython 是 python的超集, 所以cython 中可以写任何python, 调用python库
3 使用
1 file.h file.cc, cy_file.pyx
file.cc 中包含正常的C/C++ 代码
file.h 包含函数声明
cy_file.pyx 包含C 函数引用, python代码, 直接转化为标准C 代码.
2 使用 cy_file.pyx 引用 file.cc 中的实现函数
cdef extern from "file.h":
void plus(double *a, double *b, double *r, int n, int m)
使用 python 封装函数
def cython_plus(np.ndarray[double, ndim=2, mode="c"] a not None,
np.ndarray[double, ndim=2, mode="c"] b not None,
np.ndarray[double, ndim=2, mode="c"] r not None,
times not None):
plus(
a.shape[0],
a.shape[1],
3 编译
PYTHON3FLAGS = `python3.6-config --cflags --libs --ldflags`
1 g++ file.cc -c -o file.o
仅编译(-c) file.cc (目的是编译导出函数 plus 的实现)
这里仅仅进行编译, 不做链接,不生成程序或者库
2 cython -3 cy_file.pyx (cy_file.c)
转化 cython 代码为 C 代码(会包含很多python API 扩展时用的函数 --- PyInit, PyModul ..... )
3 g++ $(PYTHON3FLAGS) cy_file.c -fPIC -c -o cy_file.o
必须 带上 Python.h 进行编译, 不然无头文件
!!! 这个cy_file.c 就是正常的 C源码, 可以直接使用了. 但是使用时 需要链接必备的库 --- PYTHON3FLAGS
4 g++ --shared -o cy_file.so $(PYTHON3FLAGS) cy_file.o file.o
链接 cy_file.o file.o 为 cy_file.so
注意,这里 $(PYTHON3FLAGS) 一定要放在 --shared -o cy_file.so 之后.
这里介绍的都是简单一个文件的,当使用多个文件时
1 g++ file.cc -c -o file.o
g++ file1.cc -c -o file1.o
g++ file2.cc -c -o file2.o
g++ file3.cc -c -o file3.o
2 cython -3 cy_file.pyx
3 g++ $(PYTHON3FLAGS) cy_file.c -fPIC -c -o cy_file.o
ar -cr cy_file.a cy_file.o file.o file1.o file2.o file3.o
ranlib cy_file.a
打包所有需要的C源码到 静态链接库 .a 文件中
ar
-c 创建库
-r 插入文件
ranlib 更新库
4 g++ --shared -o cy_file.so -Wl,-soname=cy_file.so,--whole-archive cy_file.a $(PYTHON3FLAGS)
或者
4 g++ --shared -fPIC -o cy_file.so cy_file.o file.o file1.o file2.o file3.o $(PYTHON3FLAGS)
注意!!!
0 编译不需要查找引用函数的定义, 只编译自己就好了.
1 cython -3 cy_file.pyx 生成的 C程序
1 带有Python.h
2 使用Python API C++ 扩展python模块的必要方法
2 编译 file.o 等文件 不能链接 必须使用-c
3 编译 cy_file.c 必须使用 g++ $(PYTHON3FLAGS) cy_file.c -fPIC -c -o cy_file.o
1 $(PYTHON3FLAGS)
2 -fPIC ???
4 链接 $(PYTHON3FLAGS) 必须放到 --shared -o cy_file.so 之后.