此处参考官网说明:
pyinstaller [options] script [script …] | specfile
所以最简单的用法如下,即可打包
pyinstaller myscript.py
这个操作即可完成打包,会执行如下操作:
Writes myscript.spec in the same folder as the script.
Creates a folder build in the same folder as the script if it does
not exist.
Writes some log files and working files in the build folder.
Creates a folder dist in the same folder as the script if it does not
exist.
Writes the myscript executable folder in the dist folder.
一句话总结下就是会跟脚本同一个目录下生成 myscript.spec ,build 目录 dist目录
其中可执行程序就在dist目录里
一般情况,我们只需要打包主python脚本,如果你在pyinstaller后面包含了多个脚本,那么这些脚本都会包含在输出文件里
另外生成的myscript.spec 也可以用来生成可执行程序
pyinstaller myscript.spec
此处介绍几个常用的,更多的还是请查看官网
脚本或者spec文件
首先说明一下我的代码目录,这是用来打包智能翻译的,所以resource中还包括了语料文件和模型文件
src 所有源码的路径
—main.py frozendir.py 以及其他目录文件
resource
—dataset 这是存放语料的路径
—modle_save 模型和词库存放路径
找到主入口脚本以main.py举例,直接
pyinstaller main.py
pyinstaller会寻找所有main的依赖文件和依赖文件的依赖文件,不论引用了多少个文件,我们只需要简单的打包主文件即可
但是要注意一点,操作的时候发现,如果打包的时候,导入的包的路径,在你打包路径的上一层,比如main.py在src下,而其他文件引入代码是通过from src. xxx import xxx,这时候必须手动添加上这层路径,此时使用 --hidden-import 引入,如下:
–hidden-import=src --paths="E:\code\seq2seq”
当然不引入,启动也一定会失败,报 类似 no moudule named XXX的错误
打包的时候最头痛的是路径问题,比如程序里需要引用的图片和输入文本文件等,这些文件在我们用ide执行脚本的时候,路径是相对的或者绝对的,无论怎么写都没问题,但是到了打包的程序包里,会有如下问题:
用-F打包成一个文件,所有的资源会被解压缩到一个临时文件里,根本不知道路径是什么
打包的时候用相对路径,但是脚本执行的时候获取的路径是会根据运行脚本的位置在变化,无法锁死路径。
当然官网也给出了解决方案:
首先在源码的最外层比如我们此处是src,写一个脚本,用于frozen 路径,获取程序执行时的绝对路径
def get_base_dir():
if getattr(sys, 'frozen', False):
base_dir = os.path.dirname(os.path.abspath(sys.executable))
elif __file__:
base_dir = os.path.dirname(os.path.abspath(__file__))
return base_dir
这样无论你如何执行,路径都不会再动了
raw_file_path = os.path.join(base_dir, r".\resource\dataset\cmn.txt")
raw_zip_path = os.path.join(base_dir, r".\resource\dataset\cmn-eng.zip")
model_save_path = os.path.join(base_dir, r'.\resource\model_save\ai_net.pkl')
src_vocab_save_path = os.path.join(base_dir, r'.\resource\model_save\src_vocabulary.pkl')
tgt_vocab_save_path = os.path.join(base_dir, r'.\resource\model_save\tgt_vocabulary.pkl')
这样路径就能被固定下来了,例如这里resource的目录是、在可执行程序里的同级目录下的resource目录下,当然resource在打包的时候也需要配合打包到这个目录,下面是怎么配合打包resource目录。
pyinstaller.exe main.py --distpath="..\exe" --add-data="E:\work\code\seq2seqattention\resource\dataset\*;.\resource\dataset\." --add-data="E:\work\code\seq2seqattention\resource\model_save\*;.\resource\model_save"
4.最后一点就是注意资源文件如果包含多层目录,多层的打包方式,可以详细看下上面的例子
实操的时候发现pyinstaller 打包的时候,如包含多层就必须一对一都写入,否则打出来的路径会缺失
比如resource下面包含了dataset和model_save,必须一一对应的打包,否则很可能就缺失了一层
5.所有都写完之后,可以现在cmd活着powershell等上执行以下,看是否报错。
如果直接点击打开,很可能闪退,什么都看不到
此时如果是打包到一个目录的方式,就可以在dist目录(未指定打包到其他目录的话)下看到main.exe也可以看到resource目录了
下面是我完成打包一个机器翻译的源码的过程:
pyinstaller.exe main.py --distpath="..\exe" --add-data="E:\work\code\seq2seqattention\resource\dataset\*;.\resource\dataset\." --add-data="E:\work\code\seq2seqattention\resource\model_save\*;.\resource\model_save"