常见的有PyInstaller和Nuitka
此处用PyInstaller举例,Nuitka配置麻烦,而且我不在意速度和大小,所以使用更方便的选择
无论是PyInstaller和Nuitka,网上都有人做出来GUI界面以便打包,需要的可以自己找
各个工具都有的选项
pip install pyinstallermain.py,执行命令pyinstaller main.pydist目录下默认为-D,表示生成文件夹,可指定-F生成单文件
如果是-D,可通过--contents-directory指定内容目录,默认为_internal,打包目录下就会有main.exe和_internal,具体内容在_internal里,
你可以设置--contents-directory为.来让所有内容都放在根目录下
注意:在以前的PyInstaller版本,还没有--contents-directory
如果打包main.py,则最终文件名为main.exe,可通过-n指定文件名
默认含控制台,可以看到print的输出,可指定-w无控制台,常用于GUI程序
假如你有个语言文件,可以通过--add-data添加,举例:--add-data "lang.json:.",将lang.json添加到内容目录下
对于执行文件和和动态库,可通过--add-binary添加,格式一样,不同在于二进制文件会进行解析,确定他们的依赖也会被打包,能正常运行
通过--hidden-import添加模块,有的模块可能是通过__import__导入的,打包时没被检查到,导致运行时出错,需要手动指定
通过--exclude-module删除模块,假如你的代码测试时会用aaa.bbb,但运行时不会,可以:--exclude-module aaa.bbb
还有个-p选项,告诉PyInstaller你的代码在哪些目录下,比如你的源码在src下,就需要-p src确保能打包src下代码,等同于打包时的PYTHONPATH
-i FILE添加图标,--version-file FILE添加版本信息
版本信息的格式有固定需求,推荐找一个exe文件,用pyi-grab_version some.exe > v.txt读取他们的版本信息,然后修改为自己的信息
当你执行了一遍打包命令后,就会生成spec文件,下次运行时,直接pyinstaller your.spec就行
其实就是一个Python文件,里面定义了打包的参数,还有几个类,可以通过自己编写内容来实现自定义打包,比如我在第一行加个print(1),运行时就能看到
具体分析一下
a = Analysis(['temp.py'],: 基于temp.py文件分析所有的依赖等等内容pyz = PYZ(a.pure): 将a.pure中的内容打包成PYZ文件,也就是你的源码exe = EXE(pyz, a.scripts,: 创建最终的exe文件,和内容目录coll = COLLECT(exe: 收集依赖和资源到最终目录复制全部,粘贴全部,改个变量名即可
单文件的本质是将所有内容压缩到一个文件里,运行单文件时会将所有内容解压到临时文件中,这意味着
这会导致很多错误,举个例子
import os
import sys
print(sys.path)
if hasattr(sys, 'frozen'):
base_path = sys._MEIPASS
print(base_path)
print(__file__)
print(os.getcwd())
print(sys.executable)
else:
print(__file__)
print(os.getcwd())
print(sys.executable)
开发时输出
['D:\\PythonProjects\\Learn\\test', 'D:\\Python39\\python39.zip', ...
D:\PythonProjects\Learn\test\temp.py
D:\PythonProjects\Learn\test
D:\Python39\python.exe
可以看到sys.path正常,__file__指向当前文件,os.getcwd()正常,sys.executable为Python
单文件输出(命令为dist\temp.exe)
['C:\\Users\\kgg\\AppData\\Local\\Temp\\_MEI147042\\base_library.zip', 'C:\\Users\\kgg\\AppData\\Local\\Temp\\_MEI147042\\lib-dynload', 'C:\\Users\\kgg\\AppData\\Local\\Temp\\_MEI147042']
C:\Users\kgg\AppData\Local\Temp\_MEI147042
C:\Users\kgg\AppData\Local\Temp\_MEI147042\temp.py
D:\PythonProjects\Learn\test
D:\PythonProjects\Learn\test\dist\temp.exe
可以看到sys.path的路径都是临时文件里的,如果你在执行文件的目录下放一个模块,import会找不到模块
打包后的文件会有个sys.frozen和sys._MEIPASS变量,sys._MEIPASS保存的是临时目录的路径
__file__看似指向模块的路径,实际上根本没有这个文件
os.getcwd()正常
sys.executable为执行文件
解决方法
.,直接避免所有找不到资源问题尤其是PyQt,这个崩了没有一点提示,解决也简单,多用日志,输出文件,捕捉错误即可
Win10打包的程序不一定能在Win7上运行,一般是缺少DLL或者依赖库不支持,换成要么在Win7里打包,要么换成Python3.7版本再打包
打包后的内容目录下有很多dll文件,但其实这些都是系统自带的……,完全可以删掉来简化目录,但如果要确保它能在更多系统上运行,则不能删除