Cython编译动态库、引用C/C++文件
阅读原文时间:2023年07月08日阅读:3

将某些.py 编译成动态库

设置好要编译的module们:

compile_to_c_modules = [
    'package.module'
]

将它们转换成cythonize可识别的参数:

def module_to_path(module):
    """转成路径形式"""
    return module.replace('.', os.path.sep) + '.py'

def get_module_dir(module):
    """获得module所在的目录"""
    dir_path, _ = os.path.split(module_to_path(module))
    return dir_path

def make_extension(module):
    """转换成`cythonize`可识别的参数"""
    ext_path = module_to_path(module)
    if not os.path.exists(ext_path):
        return None
    return Extension(
        module,
        [ext_path],
        include_dirs=['.'],
    )

extensions = list(filter(lambda i: i is not None, [make_extension(name) for name in compile_to_c_modules]))
print('\n'.join([e.sources[0] for e in extensions]))
# package/module.py 该路径需要是相对setup.py来说的

然后在setup函数里配置它:

setup(
    name='package_name',
    packages=['pakcage'],
    ext_modules=cythonize(extensions)
)

管理员权限运行:

python setup.py build_ext

就能编译出动态库.so/.dll。加上inplace参数:

python setup.py build_ext --inplace

动态库就会在源文件所在的同一目录下,只要有动态库就可以正常import

默认情况下是编译出本机操作系统能用的动态库,但build_ext也有参数可以主动选择OS。

引用C/C++文件里的函数

(还没有尝试过,参考这里这里

  1. 首先需要有想使用的C/C++源文件、头文件
  2. 编写.pyd文件,告诉后面要写的.pyx文件可以用哪些C里面的函数/类
  3. 编写.pyx文件,用一层python函数/类来包装.pyd用到的那些C里面的函数/类
  4. 最后在python代码里引用.pyx文件定义的类即可

如果想要运行,需要把.pyx文件之类的文件添加到cythonize函数的参数里,让它生成build_ext可以直接编译和链接的.c文件,最后需要通过build_ext编译成动态库才能运行

扩展

生成一些build_ext可以直接编译和链接的.c文件(如果在cythonize函数里设置参数的话,也可以转换出cpp文件),并返回ext_modules可以识别的Extension类实例。

如果把cythonize写在了setup函数里,那么但凡调用了setup函数(也即调用了cythonize函数,其实也就是执行任何python setup.py命令),就会生成这个.c文件。

ext_modules指定的一些模块,编译和链接成动态库,参数--inplace可以把动态库就放在源码的位置。它只需要.c文件(或.cpp),如果是.py转出来的.c的话,到这一步.py可以不需要了。