Python使用Cython+MinGW编译Pyd动态链接库

Python是解释型编程语言,代码可以不经过编译直接被解释器执行,如果直接开源发布py程序,对于某些不应公开的源码来说无疑是不可取的。那么如何安全地发布py程序而又不被反编译呢,经过对比pyd是最合适的发布方式。pyd是python源码经过Cython转换后再编译而来的Windows系统下Python可用的动态链接库,与dll动态链接库文件类似,区别在于pyd库可以被python直接引用,Linux系统下编译结果为so动态链接库。

一、概念及关系

1.Python

Python是解释型动态编程语言,与JavaScript一样是边解释边执行。Python提供了高效的高级数据结构,还能简单有效地面向对象编程。Python语法和动态类型,以及解释型语言的特性,使它成为多数平台上写脚本和快速开发应用的编程语言,随着版本的不断更新和语言新功能的添加,逐渐被用于独立的、大型项目的开发。

2.Cython

Cython编程语言,它通过类似Python的语法来编写C扩展并可以被Python调用.既具备了Python快速开发的特点,又可以让代码运行起来像C一样快,同时还可以方便地调用C library。

3.MinGW

MinGW,即 Minimalist GNU For Windows。它是一些头文件和端口库的集合,该集合允许在没有第三方动态链接库的情况下使用 GCC(GNU Compiler C)产生 Windows32 程序。MinGW 并不只是一个 C/C++ 编译器,而是一套 GNU 工具集合。除开 GCC (GNU 编译器集合) 以外,MinGW 还包含有一些其他的 GNU 程序开发工具 (比如 gawk bison 等等)。

他们的关系是python源码经过cython生成c文件,再通过MinGW编译成pyd动态链接库。pyd作为python的动态链接库,可以被py程序直接import使用。

二、Cython安装

Cython作为python模块,通过pip包管理器进行安装。

pip install cython

查看是否安装成功可以通过查看pip包列表

pip list

三、MinGW安装

1.下载安装

下载离线免安装版(https://sourceforge.net/projects/mingw-w64/files/mingw-w64/)(请下载最新的x86_64-posix-seh版本,win32版本不支持c++11的thread库),解压到非中文目录中(路径中不得包含中文),建议解压到D:\mingw64

2.添加环境变量

在环境变量path中添加路径D:\mingw64\bin(建议用户变量和系统变量都添加上路径)。

3.添加distutils.cfg

Python安装目录\Lib\distutils\中添加distutils.cfg文件,并写入以下内容。

[build]
compiler=mingw32

[build_ext]
compiler = mingw32

四、测试编译

相关的软件编译器安装好后,就可以测试编译py文件为pyd,目的是通过报错信息来对应解决问题。

1.新建build.py文件

Python项目根目录下新建build.py文件,用于执行编译。

# build.py
from distutils.core import setup
from Cython.Build import cythonize

# cythonize第一个参数为路径数组,路径数组可包含多个路径。
# libs/a/*.py表示libs/a/下所有py文件
setup(
    name='My pyd',
    ext_modules = cythonize(['libs/a/*.py','libs/b/*.py'], language_level=3),
)

2.执行cmd命令编译

python build.py build

五、错误及解决

(一)Unable to find vcvarsall.bat

(venv) C:\Users\Administrator\PycharmProjects\pythonPydTest>python build.py build
running build
running build_ext
building 'lib_a' extension
error: Unable to find vcvarsall.bat

解决:问题是没有正确安装vc++编译器,按上面步骤安装MinGW即可。

(二)Unknown MS Compiler version 1928

(venv) C:\Users\Administrator\PycharmProjects\pythonPydTest>python build.py build
running build
running build_ext
Traceback (most recent call last):
  File "build.py", line 4, in <module>
    setup(
  File "D:\Program Files\Python38\lib\distutils\core.py", line 148, in setup
    dist.run_commands()
  File "D:\Program Files\Python38\lib\distutils\dist.py", line 966, in run_commands
    self.run_command(cmd)
  File "D:\Program Files\Python38\lib\distutils\dist.py", line 985, in run_command
    cmd_obj.run()
  File "D:\Program Files\Python38\lib\distutils\command\build.py", line 135, in run
    self.run_command(cmd_name)
  File "D:\Program Files\Python38\lib\distutils\cmd.py", line 313, in run_command
    self.distribution.run_command(command)
  File "D:\Program Files\Python38\lib\distutils\dist.py", line 985, in run_command
    cmd_obj.run()
  File "D:\Program Files\Python38\lib\distutils\command\build_ext.py", line 306, in run
    self.compiler = new_compiler(compiler=self.compiler,
  File "D:\Program Files\Python38\lib\distutils\ccompiler.py", line 1032, in new_compiler
    return klass(None, dry_run, force)
  File "D:\Program Files\Python38\lib\distutils\cygwinccompiler.py", line 282, in __init__
    CygwinCCompiler.__init__ (self, verbose, dry_run, force)
  File "D:\Program Files\Python38\lib\distutils\cygwinccompiler.py", line 157, in __init__
    self.dll_libraries = get_msvcr()
  File "D:\Program Files\Python38\lib\distutils\cygwinccompiler.py", line 86, in get_msvcr
    raise ValueError("Unknown MS Compiler version %s " % msc_ver)
ValueError: Unknown MS Compiler version 1928

解决:按提示意思是找不到对应1928版本的编译器,我们需要在python中指定1928的编译器。

修改Python安装目录\Lib\distutils\cygwinccompiler.py文件,在get_msvcr函数中else之前添加判断代码,判断msc_ver1928,并指定编译器为vcruntime140

elif msc_ver == '1928':
            # MinGW
            return ['vcruntime140']

1928是版本号,根据错误提示进行修改

完整代码:

def get_msvcr():
    """Include the appropriate MSVC runtime library if Python was built
    with MSVC 7.0 or later.
    """
    msc_pos = sys.version.find('MSC v.')
    if msc_pos != -1:
        msc_ver = sys.version[msc_pos+6:msc_pos+10]
        if msc_ver == '1300':
            # MSVC 7.0
            return ['msvcr70']
        elif msc_ver == '1310':
            # MSVC 7.1
            return ['msvcr71']
        elif msc_ver == '1400':
            # VS2005 / MSVC 8.0
            return ['msvcr80']
        elif msc_ver == '1500':
            # VS2008 / MSVC 9.0
            return ['msvcr90']
        elif msc_ver == '1600':
            # VS2010 / MSVC 10.0
            return ['msvcr100']
        elif msc_ver == '1928':
            # MinGW
            return ['vcruntime140']
        else:
            raise ValueError("Unknown MS Compiler version %s " % msc_ver)

(三)error: command ‘D:\Program Files\mingw64\bin\gcc.exe’ failed with exit status 1

(venv) C:\Users\Administrator\PycharmProjects\pythonPydTest>python build.py build
running build
running build_ext
building 'lib_a' extension
creating build
creating build\temp.win-amd64-3.8
creating build\temp.win-amd64-3.8\Release
creating build\temp.win-amd64-3.8\Release\libs
D:\Program Files\mingw64\bin\gcc.exe -mdll -O -Wall -IC:\Users\Administrator\PycharmProjects\pythonPydTest\venv\include "-ID:\Program Files\Python38\include" "-ID:\Prog
ram Files\Python38\include" -c libs\lib_a.c -o build\temp.win-amd64-3.8\Release\libs\lib_a.o
libs\lib_a.c:215:41: warning: division by zero [-Wdiv-by-zero]
     enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) };
                                         ^
libs\lib_a.c:215:12: error: enumerator value for '__pyx_check_sizeof_voidp' is not an integer constant
     enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) };
            ^~~~~~~~~~~~~~~~~~~~~~~~
error: command 'D:\\Program Files\\mingw64\\bin\\gcc.exe' failed with exit status 1

解决:执行cmd编译命令是需加上-DMS_WIN64参数

python build.py build_ext --inplace -DMS_WIN64
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值