项目场景:
平时在打包python程序代码的时候都是利用cython将单个文件打包成单个so文件,但这样的打包方式管理起来非常的不方便,如何将要你的项目代码整个打包成1个单独的so文件然后给别人调用?
环境需求
1. python>=3.6
2. cython >=0.29.2
文件结构:
├── testfile # 你的项目代码文件
│ ├── test_a.pyx # 测试A的脚本文件
│ ├── test_b.pyx # 测试B的脚本文件
│ ├── bootstrap.pyx # 将项目打包的文件模块
│ └── __init__.py # 初始化文件
├── setup.py # 打包脚本
└── testp.py # 测试脚本
__init__.py 中的代码
from . import bootstrap # 打包的函数 bootstrap.bootstrap_cython_submodules()
bootstrap.pyx 中的代码
import sys import importlib import importlib.abc # 选择正确的初始函数 class CythonPackageMetaPathFinder(importlib.abc.MetaPathFinder): def __init__(self, name_filter): super(CythonPackageMetaPathFinder, self).__init__() self.name_filter = name_filter def find_spec(self, fullname, path, target=None): if fullname.startswith(self.name_filter): # 使用这个扩展文件,而不是其他模块的pyinit函数: loader = importlib.machinery.ExtensionFileLoader(fullname, __file__) return importlib.util.spec_from_loader(fullname, loader) # 将自定义查找器/加载 => sys.meta_path: def bootstrap_cython_submodules(): sys.meta_path.append(CythonPackageMetaPathFinder('foo.'))
test_a.pyx 代码
def print_me(): print("我是test_A")
test_b.pyx 代码
def print_me(): print("我是test_B")
setup.py 代码
from setuptools import setup, find_packages, Extension from Cython.Build import cythonize sourcefiles = ['foo/bootstrap.pyx', 'foo/bar_a.pyx', 'foo/bar_b.pyx'] extensions = cythonize(Extension( name="foo.bootstrap", sources = sourcefiles, )) kwargs = { 'name':'foo', 'packages':find_packages(), 'ext_modules': extensions, } setup(**kwargs)
执行脚本
1. python setup.py build_ext --inplace
文件结构改变如下
├── build
│ ├── lib.linux-x86_64-3.8
│ │ └── foo
│ │ └── bootstrap.cpython-38-x86_64-linux-gnu.so
│ └── temp.linux-x86_64-3.8
│ └── foo
│ ├── test_a.o
│ ├── test_b.o
│ └── bootstrap.o
├── testfile
│ ├── test_a.c
│ ├── test_a.pyx
│ ├── test_b.c
│ ├── test_b.pyx
│ ├── bootstrap.c
│ ├── bootstrap.cpython-38-x86_64-linux-gnu.so
│ ├── bootstrap.pyx
│ └── __init__.py
├── setup.py
└── testp.py
testp.py 此时测试代码
import testfile.test_b as b import testfile.test_a as a b.print_me() a.print_me()