使用Cython将Python打包成wheel文件

技术文档网 2021-05-12
Wheel文件

Wheel是Python的一种打包格式(.whl),目的是支持不需要编译的安装过程并且能够起到保护Python源码的作用。它实际上也是一种压缩文件,将.whl的后缀改为.zip即可可看到压缩包里面的内容。Wheel现在被认为是Python的二进制包的标准格式。

打包过程

依赖:

  1. distutils
  2. setuptools
  3. Cython
  4. 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

相关文章

  1. Django基本命令

    Django基本命令 打开linux终端直接在终端中输入以下命令即可。 新建一个django project 命令:django-admin.py startproject project-nam

  2. 17个新手常见Python运行时错误

    17个新手常见Python运行时错误 当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂。这里列出了常见的的一些让你程序 crash 的运行时错误。 当初学 Python

  3. Python+SQLite真的有用吗?

    SQLite是个很简单的数据库,一个文件就可以搞定,存储上千万行的数据也没问题,图形界面程序有很多,管理很方便,用Python可以编程操作,也很简单,一切都似乎很完美。 我导入了几千万行的数据进SQL

  4. os各种各样的操作系统接口

    这个模块提供了一种使用操作系统相关功能的移动方式。如果您只想读取或写入一个文件,请查看open(),如果您想要操作路径,请参见操作os.path模块,如果您想要读取命令行上所有文件中的所有行,请参阅f

  5. 通过webpy和nginx-with-fastcgi搭建web.py

    这一节讲解的是如何使用Nginx和FastCGI搭建Web.py应用 环境依赖的软件包 Nginx 0.8.* or 0.7.* (需要包含fastcgi和rewrite模块)。 Webpy 0.3

随机推荐

  1. Django基本命令

    Django基本命令 打开linux终端直接在终端中输入以下命令即可。 新建一个django project 命令:django-admin.py startproject project-nam

  2. 17个新手常见Python运行时错误

    17个新手常见Python运行时错误 当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂。这里列出了常见的的一些让你程序 crash 的运行时错误。 当初学 Python

  3. Python+SQLite真的有用吗?

    SQLite是个很简单的数据库,一个文件就可以搞定,存储上千万行的数据也没问题,图形界面程序有很多,管理很方便,用Python可以编程操作,也很简单,一切都似乎很完美。 我导入了几千万行的数据进SQL

  4. os各种各样的操作系统接口

    这个模块提供了一种使用操作系统相关功能的移动方式。如果您只想读取或写入一个文件,请查看open(),如果您想要操作路径,请参见操作os.path模块,如果您想要读取命令行上所有文件中的所有行,请参阅f

  5. 通过webpy和nginx-with-fastcgi搭建web.py

    这一节讲解的是如何使用Nginx和FastCGI搭建Web.py应用 环境依赖的软件包 Nginx 0.8.* or 0.7.* (需要包含fastcgi和rewrite模块)。 Webpy 0.3