Python .py生成.pyd文件并打包.exe 的注意事项说明
最近用python写了一个小程序,想发布出去让人试用又不想暴露源码,搜索了一下发现将py文件编译成pyd文件就能达到目的。
转换过程很简单,但是在调用pyd文件并且打包为单个exe文件的时候遇到一个坑,搞了一天才解决,在这里分享一下。
首先安装cython库个人比较喜欢用清华的镜像库,速度快。
pip install Cyphton -i https://pypi.tuna.tsinghua.edu.cn/simple然后创建一个setup.py文件
写入以下内容:
from distutils.core import setupfrom Cython.Build import cythonizesetup(ext_modules=cythonize('BetaV14.py'))BetaV14.py就是要转换为pyd文件的代码文件
命令行输入:
python setup.py build_ext --inplace
会在.py文件目录下生成一个BetaV14.cp37-win_amd64.pyd文件,文件名中“.cp37-win_amd64”这一段可以删除,不删除也可以正常调用;但原文件名字段不能改变。
接下来需要打包发布为.exe文件我用的是pyinstaller,还是用清华镜像库安装。
pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple
根据一些教程,有的说在命令行直接输入:
pyinstaller -F BetaV14.py
就能直接引用pyd文件打包发布exe文件,但是在我这里出现文件缺失的错误:
ValueError: Module file F:python项目1BetaV14.py is missing
继续查找问题,发现需要用一个入口程序来导入pyd文件,于是创建一个main.py文件,import刚才生成的模块,pyd文件默认优先级高于py文件,可以在后面解包exe文件来验证。
import BetaV14if __name__ == ’__main__’: BetaV14()
这里需要注意的是程序的__main__入口只能有一个,如果源py文件中有定义main入口,需要注释掉并调整代码缩进,否则通过main.py调用pyd文件遇到if name == ‘main’:之后的代码都不会运行。
接着命令行输入:pyinstaller -F main.py
打包成.exe文件,在dist目录下发现main.exe文件大小只有5M,之前采用py文件打包的程序有接近50M,运行之后闪退。这个问题想了半天才想出来,可能是引用了大量的第三方库没有打包进去,于是将源py文件头部import部分全部复制到main.py文件头部。
import win32guiimport win32apiimport win32conimport time import randomimport datetimeimport os,sysimport configparserimport numpy as npfrom PIL import Imagefrom scipy.signal import convolve2dimport http.clientimport subprocessimport BetaV14if __name__ == ’__main__’: BetaV14()
再次用命令pyinstaller -F main.py打包,得到正常大小的.exe文件,点击能正常运行。
接下来我们用pyinstxtractor.py(不清楚该脚本是否涉及著作权,请自行搜索)解包exe文件验证一下,命令行输入:
python pyinstxtractor.py main.exe
会得到一个main.exe_extracted文件夹,在文件夹下发现文件BetaV14.pyd,说明通过引用pyd文件打包成功。
在此作为一个初学者记录一下自己遇到的坑,让大佬们见笑了。
补充:python打包编译成pyd或者_python之setup.py的那些事
今天偶然对setup.py产生了兴趣,以前只知道可以用它来安装包,例如
python setup.py build ->python setup.py install.当然前提你下载的这个源码包是压缩的,之前对这个理解并不深,今天偶然看见pip install -e . 的用法,然后串起来想了一下。
我的目录结构如上,首先我创建了一个setuptutorial的directory,然后我在下面创建了greet_pkg的python package,并且在setuptutorial下面创建了setup.py如下
from setuptools import setup, find_packages setup( name=’greet’, version=’1.0.0’, packages=find_packages(include=[’greet_pkg’, ’greet_pkg.*’]), url=’’, license=’uestc’, author=’jack’, author_email=’2444093230@qq.com’, description=’test package’, py_modules=[’greet2’], install_requires=[’pyjokes’])
greet2.py如下
def greet2(name): print( ’hello’,name,’this is greet2’ )
在greet_pkg下面下了一个greet.py如下
import pyjokesdef greet(name): print(’hello!’, name, f’im telling you a joke {pyjokes.get_joke()}’)整体目录结构和setup.py就如上所示
接下来好戏开场了,如果我要在任意其他文件里面使用到我定义的greet()方法,以前的做法是按照import规则在其他文件里面导入,当然如果写的不规范,及其的容易出问题,这里我提供另外一个思路,在setuptutorial下面使用pip install -e . 命令,将setup.py里面包含的package和py_module安装到Libary root下,当然他的实际的location不是在Libary root下,这个你可以在pip install -e . 之后使用pip show greet 查看他的信息.
到这里就完了吗?当然没有,这个就是之前的python setup.py build 的作用,我这里猜测大概率是把tar.gz包转化成我上述的目录结构一样的directory。
而python setup.py install 的作用就类似于pip install ’-e’ . 。而且python setup.py install 之后的greet包是真的存在于sitepackages里面的。
setup.py除了上述安装包的作用,还可以是他的逆过程如 python setup.py sdist 成greet.tar.gz,这样就有上述的装包的过程先build再install。
还可以使用setup.py将py文件转化为pyd,也可以说将pyx文件转化为pyd,
from setuptools import setup# from distutils.core import setupfrom Cython.Build import cythonize # setup(# name=’hello’,# ext_modules=cythonize([’sayhi.py’])# )
然后运行python setup.py build_ext --inplace就可以了!
pyd文件可以很好的隐蔽py文件里面的实现,和linux下的so文件类似。
有类似py->pyd功能的有easycython模块,可以直接pip安装。
有人可能会说pyc也看不见源码吗?
但是他可以被反编译23333
至于如何将py编译成pyc或pyo
可以使用py_compile或者compileall,不了解的可以自行搜索一下,都有很多的例子,还有针对pyc的反编译库,都可以搜到,至此setup.py我所了解的功能都谈完了,里面还有很多参数可以灵活配置,实现更加炫酷的效果可以查看这个链接setup.py
相关文章: