使用Cython将Python打包成wheel文件 - AruiLR/MyNote GitHub Wiki
Wheel文件
Wheel是Python的一种打包格式(.whl),目的是支持不需要编译的安装过程并且能够起到保护Python源码的作用。它实际上也是一种压缩文件,将.whl的后缀改为.zip即可可看到压缩包里面的内容。Wheel现在被认为是Python的二进制包的标准格式。
打包过程
依赖:
- distutils
- setuptools
- Cython
- wheel
以上是在打包过程中需要用到的工具,可通过pip快速安装。
目录结构

将需要打包的Python工程按照上述目录结构组织,其中root为打包后的Module,__init__.py是实现import所必须的。接下来编写setup.py进行打包即可。
setup.py
Linux
from setuptools import setup
from setuptools.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
setup(
name="MyModule" # 模块名称 import MyModule,
ext_modules=cythonize(
[
Extension("pkg1.*", ["root/pkg1/*.py"]),
Extension("pkg2.*", ["root/pkg2/*.py"]),
Extension("1.*", ["root/*.py"])
],
build_dir="build",
compiler_directives=dict(
always_allow_keywords=True
)),
cmdclass=dict(
build_ext=build_ext
),
packages=["pkg1", "pkg2"] # packages=[]时打包后的wheel文件中不含源码(.py)
)
python setup.py bdist_wheel
Windows
from setuptools import setup
from setuptools.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
from pathlib import Path
import shutil
class MyBuildExt(build_ext):
def run(self):
build_ext.run(self)
build_dir = Path(self.build_lib)
root_dir = Path(__file__).parent
target_dir = build_dir if not self.inplace else root_dir
self.copy_file(Path('root/pkg1') / '__init__.py', root_dir, target_dir)
self.copy_file(Path('root/pkg2') / '__init__.py', root_dir, target_dir)
self.copy_file(Path('root') / '__init__.py', root_dir, target_dir)
def copy_file(self, path, source_dir, destination_dir):
if not (source_dir / path).exists():
return
shutil.copyfile(str(source_dir / path), str(destination_dir / path))
setup(
name="MyModule",
ext_modules=cythonize(
[
Extension("pkg1.*", ["root/pkg1/*.py"]),
Extension("pkg2.*", ["root/pkg2/*.py"]),
Extension("1.*", ["root/*.py"])
],
build_dir="build",
compiler_directives=dict(
always_allow_keywords=True
)),
cmdclass=dict(
build_ext=MyBuildExt
),
packages=[],
)
**注意:**在Windows下打包时由于系统原因无法编译__init__.py,要解决这个问题,我们在构建项目的其余部分后从源码树中复制__init__.py文件,通过覆盖setup.py中的build_ext类。
安装
pip install *.whl