Python程序打包--PyInstaller

来源:互联网 发布:在淘宝上面卖什么好 编辑:程序博客网 时间:2024/05/16 05:03

    Python程序打包,首选“PyInstaller”,操作简单,功能丰富,而且它还支持Python2.7和Python3.3+。之前用的py2exe则不支持python3.5。PyInstaller的官网如下:

     http://www.pyinstaller.org/

    就像官网首页所说的,PyInstaller简单到仅需两条命令即可搞定从安装到打包你的程序:

1)安装PyInstaller

pip install pyinstaller


2)打包python程序

pyinstaller yourprogram.py

    本文不想复述PyInstaller的简单应用,而是通过我遇到的一个案例,来探索PyInstaller的一些稍高级点的应用,它包括:

1)python包装EXE;

2)生成和修改.spec文件;

3)onefolder和onefile;

4)添加icon;


一、需求

    我现有一个C/C++程序,它包含两个文件:CheckLicense.exe和EncryptorDll.dll。我一般将它打成一个压缩包给FAE工程师在使用。使用的时候需要先先解压,再运行“CheckLicense.exe”,稍稍有点不方便。

    我就想:既然PyInstaller可以将Python程序打包成一个文件,那么有木有可能我用python脚本调用这个CheckLicense.exe”,然后把“python脚本”、CheckLicense.exe”和“EncryptorDll.dll”一起用PyInstaller打包成一个EXE文件?


注:有些压缩软件也支持将一个文件夹压缩为一个exe文件,解压缩自动运行指定的文件。但是,这个需要目标电脑安装该压缩软件。


二、探索

1,直接打包

    在我之前的博客:http://blog.csdn.net/sagittarius_warrior/article/details/72831039

    如果python脚本中通过ctypes调用了某个DLL文件,PyInstaller在打包的时候,除了会自动搜索“依赖的库”、“依赖的python脚本”,还会将“ctypes调用的DLL文件”和该文件依赖的“运行时库”,并打包!是不是很智能?

    于是,我想直接写如下脚本,PyInstaller会不会也将我要的文件CheckLicense.exe”和“EncryptorDll.dll”都打包:

#CheckLicenseEx.pyimport osos.system('CheckLicense')

    将该脚本与CheckLicense.exe”和“EncryptorDll.dll”放在同一个目录下,运行该脚本,可以正常调用CheckLicense.exe”。

    使用如下命令打包:

pyinstaller --onefile CheckLicenseEx.py

    在dist目录下生成了“CheckLicenseEx.exe”,运行,跳出一个console,但貌似没有执行“CheckLicense.exe”。

    这么说来,直接打包是不行的!


2,修改“spec文件”

    通过浏览PyInstaller -> Manual -> Using Spec Files 

    https://pyinstaller.readthedocs.io/en/stable/spec-files.html

    于是知道,如果PyInstaller没有自动打包的文件,可以通过修改spec文件,进行手动添加。步骤如下:

1)生成spec文件

    pyi-makespec options name.py [other scripts ...]

    对于我的程序,具体命令如下:

pyi -makespec --onefile CheckLicenseEx.py


    注意:在生成spec文件的时候,需要将其他选项都带上,如“--onefile”。


2)修改spec文件

    将需要额外打包的文件,添加到datas项,如下:

             datas=[('CheckLicense.exe', '.'), ('EncryptorDll.dll', '.')],


    如上,datas是一个list,而该list的内部元素是二元组,前者表示待打包的文件或文件夹,一般来说推荐使用全路径;后者表示打包后的位置,dot表示当前文件夹。

    

3)使用spec文件生成

pyinstaller CheckLicenseEx.spec


注意:此时仅支持如下选项:

  • –upx-dir=
  • –distpath=
  • –workpath=
  • –noconfirm
  • –ascii
而像“--onefile”等已经不支持了,故需要在生成spec文件时将那些命令先输入。


验证:

    将生成的CheckLicenseEx.exe拷贝到目标机器,运行,报错:“CheckLicense.exe不是可以执行文件”。但是,如果我没有用“--onefile”选项,只是生成一个文件夹,将整个文件夹拷贝到目标电脑,可以正常运行CheckLicenseEx.exe,并成功执行“CheckLicense.exe”。

    该现象非常令人迷惑!


注:PyInstaller官网文档中说:打包成onefile文件时,发布前,最好先打包成onefolder,并检查一下需要的文件是否正确打包了。onefolder模式的优势就是,方便检查。


3,程序执行路径

    对于上面提到的诡异现象,我仔细阅读了PyInstaller的文档关于onefile的工作原理:onefile实际也是在运行时,先解压到一个临时文件夹,然后执行Python脚本。

    因此,我想:onefolder可以,而onefile不行,不太可能是文件漏打包了。那么,有一种极大的可能:路径不对,导致执行该条语句时,

os.system('CheckLicense')
    python解释器在当前目录下找不到“CheckLicense.exe”。


1)打印路径

    为了验证我的想法,我决定先注释上述语句,而改为添加一些打印信息:

#CheckLicenseEx.pyimport osimport syscurrPath = sys.path[0]print(currPath)print(os.listdir(currPath))#os.system('CheckLicense')

    然后,按照之前的方法打包为onefile —— “CheckLicenseEx.exe”,运行后,报错,指向这一句

print(os.listdir(currPath))


    错误信息:currPath不是一个有效的路径。仔细查看currPath,发现其中有“...\***.zip\”。貌似PyInstaller将脚本到打包到了这个压缩文件中,而os.listdir()函数不能列出压缩文件内部的文件列表。

    我想,那会不会CheckLicense.exe”和“EncryptorDll.dll”根本就不在这个压缩文件中,而在它的上层文件夹?

    于是修改脚本:

#CheckLicenseEx.pyimport osimport syscurrPath = sys.path[0]highPath = os.path.split(currPath)print(os.path.split(currPath))print(os.listdir(highPath[0]))#print(highPath[0]+'\\CheckLicense.exe')#os.system('CheckLicense')


    还是按照上述方法打包成onefile,运行后发现:“CheckLicense.exe”和“EncryptorDll.dll”果然在那个压缩文件的上层目录。

    至此,问题定位了:CheckLicenseEx.exe”的运行目录、onefile解压后的python脚本目录和CheckLicense.exe”所在的目录各不相同。

注:关于python的路径相关函数,可以参考  http://blog.csdn.net/longshen747/article/details/17194259

2)正确路径

    我们只需如下修改脚本

#CheckLicenseEx.pyimport osimport syscurrPath = sys.path[0]highPath = os.path.split(currPath)os.system(highPath[0]+'\\CheckLicense')

    再打包,即可正确运行了!!!

4,不修改spec文件

    我们需要的是将CheckLicense.exe”和“EncryptorDll.dll”打包进onefolder或onefile。事实上,PyInstaller文档上还提到了一种方法,直接用“--add-data”命令,也可以办到。命令如下:

pyinstaller --add-data=CheckLicense.exe;. --add-data=EncryptorDll.dll;. --onefile CheckLicenseEx.py

    通过这条命令,生成的spec文件中,同样的也能看到datas项里添加了相同的内容。


5,修改程序默认图标

    PyInstaller打包的程序,默认图标比较丑,我想美化一下,可以换成自己的图标,可以用“--icon”命令,如下:

pyinstaller --add-data=CheckLicense.exe;. --add-data=EncryptorDll.dll;. --icon=umbrella.ico --onefile --clean CheckLicenseEx.py

    其中,最后的“--clean”命令是清缓存。

    下面是我的Logo


原创粉丝点击