将 py 文件编译为 pyd(原创)
将 py 文件编译为 pyd
将 py 文件编译为 pyd 可以起到保护源代码的作用,使用 cython 和 nuitka 都可以实现,cython 编译出来的 pyd 体积比较小,但是需要写 setup.py 配置文件,编译时遇到的问题也比较多;nuitka 编译出来的体积比较大,但是不用写配置文件,编译过程相对比较顺利。
使用 Cython 编译 pyd
,网上一般配合 VisualStudio 来编译,不过 VS 的体积过于臃肿,下面将使用 MingW64 编译的过程记录如下(win7 + python 3.8 32位):
1、安装 MingW64
下载 w64devkit-x86-2.2.0.7z,需要注意的是:MingW64 的版本必须与本地的 python 环境一致,32位 python 要配合 32 位的 MingW64,解压缩后将 MingW64 的 bin 路径加入到 PATH 环境变量中
打开命令行窗口,执行 gcc -v,能够正确显示 GCC 的版本号,表示已经正确安装 MingW64
2、安装 cython
pip install cython
3、编写宿主程序
假设需要保护的代码为 example.py,需要将其中代码封装到一个函数中,将 example.py编译为 pyd 文件后,需要在宿主程序中调用该函数。
原 example.py*:
print("Hello World!")
新 example.py:
# example.py
def say_hello():
print("Hello World!")
宿主程序 main.py:
# main.py
from example import *
say_hello()
4、编写编译设置文件 setup.py
在 example.py、main.py 相同目录创建 setup.py
# setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(
# 下面的 example.py 根据需要保护的脚本修改
ext_modules = cythonize("example.py", compiler_directives={'language_level' : "3"}),
include_dirs=[],
libraries=[],
library_dirs=[],
extra_compile_args=['-std=c++11'], # 如果你需要C++特性的话
)
下面是一个改良版的配置文件,可以稍加改动,执行自动将宿主程序复制到输出目录,pyd文件更名等操作
import setuptools
from distutils.core import setup
from Cython.Build import cythonize
import os
'''
该文件的执行需要的在Terminal中输入 python setup.py build_ext --inplace
使用Cpython 编译python文件,关键函数编译成pyd文件(相当于dll)
'''
# 针对多文件情况设置,单文件就只写一个就行
key_funs = ["example.py"]
setup(
name="testapp",
ext_modules=cythonize(key_funs),
)
'''
1、将编译后的pyd文件的命名更改成与原py文件一致
2、删除编译后得到的c文件和原py文件
'''
files = os.listdir(os.getcwd())
print(files)
for fi in files:
if fi.__contains__(".pyd"):
re_name = fi.split(".")[0] + ".pyd"
print(re_name)
print(fi, re_name)
os.rename(fi, re_name)
elif fi.__contains__(".c") or fi in key_funs:
os.remove(fi)
print(fi)
# 运行方式 在原目录的命令行下执行
# python setup.py build_ext --inplace
# 用 GCC 编译使用以下命令
# python setup.py build_ext --compiler=mingw32
5、编译
执行以下命令
python setup.py build_ext --compiler=mingw32
会在当前文件夹下生成 build 文件夹,其中 lib.win32-cpython-38 文件夹下包含了编译的 pyd 文件 example.cp38-win32.pyd,配合 main.py 即可脱离 cython 运行(将其更名为 example.pyd 不影响正常运行)。
补充:python_64bit + MingW64_64bit 下遇到的坑
1、Unknown MS Compiler version 1928
修改 Python 安装目录 \Lib\distutils\cygwinccompiler.py 文件,在 get_msvcr 函数中 else 之前添加判断代码,判断 msc_ver为1928,并指定编译器为 vcruntime140。
elif msc_ver == '1928':
# MinGW
return ['vcruntime140']
2、error: enumerator value for '__pyx_check_sizeof_voidp'
解决:执行编译命令时需加上-DMS_WIN64参数
python setup.py build_ext --compiler=mingw32 -DMS_WIN64
如果使用的是脚本,可以做如下修改
setup(ext_modules=cythonize(filePath), script_args=["build_ext", "-b", absPath, "-t", build_tmp_dir])
setup(ext_modules=cythonize(filePath, language_level=3), script_args=["build_ext", "-b", absPath, "-t", build_tmp_dir, "--inplace", "-DMS_WIN64"])
3、ld.exe: cannot find -lvcruntime140错误。
复制 C:\Program Files\Python\vcruntime140.dll 到一个文件夹中,执行以下命令:
gendef vcruntime140.dll
dlltool -D vcruntime140.dll -d vcruntime140.def -l libvcruntime140.a
将生成的 libvcruntime140.a 复制到 C:\ProgramFiles\Python\libs 目录即可。
附注:以下可供参考,不过本次实践都没用到
cython: 使用mingw编译器
https://blog.csdn.net/tianxifeng/article/details/103160925
https://www.cnblogs.com/cokefentas/p/16787325.html
https://blog.csdn.net/qq_30386941/article/details/126620215
使用 nuitka 编译
将 py 文件编译成 pyd
nuitka --module test.py
将 py 项目编译成 exe
# 假设主程序文件为 main.py
nuitka --onefile main.py
nuitka 无法指定 MWing64 编译器的位置,编译时默认情况下会自动下载编译器(MWing64)和依赖项(depends),也可以手工下载后解压到指定位置,再次运行 nuitka 就不会再重复下载了。
Ming64 保存位置
C:\Users<用户名>\AppData\Local\Nuitka\Nuitka\Cache\downloads\gcc\x86\14.2.0posix-19.1.1-12.0.0-msvcrt-r2
depends 保存位置
C:\Users<用户名>\AppData\Local\Nuitka\Nuitka\Cache\downloads\depends\x86

浙公网安备 33010602011771号