PyInstaller打包exe可执行文件详细教程

文章目录

  • PyInstaller
    • PyInstaller安装
      • pip安装
      • pip升级
    • PyInstaller使用
  • 如何让PyInstaller把额外的文件打包进来
  • 如何让PyInstaller把外部包打包进来
  • 解决自己的PC可以运行打包好的exe,别人PC却无法运行的问题
  • 将打包生成的文件夹转成一个单一exe

写本文的初衷是,自己在使用PyInstaller过程中踩了很多坑,花了很多时间搜了很多教程,最后才实现了打包的exe软件能够在自己以及其他人的Windows PC上都正常运行。

代码是一个交互式的医学影像标注软件,GUI通过PyQt 5,深度学习算法基于PyTorch实现,调用了基于TensorFlow的crop_and_resize实现的一个外部包RoIAlign。

大致描述一下要打包的代码包含哪些元素:

  1. 代码及代码中import的包(PyInstaller会自动打包进来)
  2. 外部包RoIAlign(手动修改.spec文件)
  3. 模型的checkpoint.pth.tar(手动修改.spec文件)

描述一下踩到的坑,希望可以帮到看到这篇文章的人。

  1. checkpoint没有被自动打包,需手动修改spec文件,然后通过spec重新进行打包。
  2. 外部包RoIAlign没有被自动打包,需手动修改spec文件,然后通过spec重新进行打包。
  3. spec的属性在其生成时已经被决定,所以在运行spec重新打包时,即使改变了参数,如-D变为-F,是无效的。
  4. 在自己的PC上可以运行,但在别人的PC上运行就闪退。

我这边的开发环境是:

  • Window 10
  • Anaconda3
  • Python 3.6.10
  • PyTorch 1.2.0

PyInstaller

基本上

PyInstaller安装

pip安装

pip install pyinstaller

pip升级

pip install --upgrade pyinstaller

PyInstaller使用

PyInstaller的使用还是非常简单的,假设主程序代码是main.py, 只需要使用以下代码即可实现。

pyinstaller main.py

官方文档可以点击 链接

当然可以按照按照自己的需求修改参数,这里列一下常用参数对应的含义。

参数 含义
-h, --help 显示PyInstaller帮助信息并退出
-v, --version 显示PyInstaller版本信息
–clean 在打包前清除PyInstaller缓存和临时文件
-D, --onedir 创建一个包含可执行文件的文件夹包(默认)
-F, --onefile 创建一个可执行的文件包
-n, --name 更改打包生成的文件的文件名
-c, --console, --nowindowed 打开用于标准I / O的控制台窗口(默认)。 在Windows上,如果第一个脚本是“ .pyw”文件,则此选项无效。
-w, – windowed, --noconsole Windows和Mac OS X:不提供标准I / O的控制台窗口。 在Mac OS X上,这也会触发构建OS X .app捆绑软件。 在Windows上,如果第一个脚本是“ .pyw”文件,则将设置此选项。 在* NIX系统中,此选项被忽略。

其他的一些参数可以点击 链接 查询。

其中,What to bundle,where to bundle部分,更建议通过spec文件来修改。
PyInstaller打包exe可执行文件详细教程_第1张图片
这边有个小建议,就是尽量不是用-F这个指令。将全部文件打包到一个可执行exe中,很容易遇到问题,且不容易debug。在用PyInstaller时,先使用-D,将文件打包到一个文件夹里,后面我再介绍用什么文件将这个文件夹转化为一个exe,易调试,简单,且可以压缩文件夹的大小。

需要调试时,用

pyinstaller -D -c main.py

这样在运行exe时,控制台窗口会弹出,方便进行调试。

调试完成,用

pyinstaller -D -w main.py

这样在运行exe时,控制台窗口不会弹出,方便使用。

如何让PyInstaller把额外的文件打包进来

上面提到我的应用里需要把深度学习模型的权重文件,就是checkpoint.pth.tar一起打包起来。

假设将打包文件放置在release文件夹中,则按照上面的操作,release文件夹中将包含以下3个文件/文件夹:
build
release
main.spec
此时我们需要修改Main.spec文件。

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(['..\\main.py'],
             pathex=['E:\\release'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='Controller',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='Controller')

修改Analysis中的datas即可。将要添加的文件的路径和添加后的路径给出即可。

a = Analysis(['..\\main.py'],
             pathex=['E:\\release'],
             binaries=[],
             datas=[('..\\checkpoint.pth.tar','checkpoint.pth.tar')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)

然后重新用main.spec打包一次。前面说过了,用.spec打包的话,更改参数无效。因此只需要

pyinstaller main.spec

即可。

完成后,在dist文件夹中,应该能找到checkpoint.pth.tar文件了。

当然了,更简单的方法,就是直接拷贝到dist里。。。也没问题

如何让PyInstaller把外部包打包进来

上面提到,我的代码中使用了一个基于TensorFlow的crop_and_resize实现的一个外部包RoIAlign
GitHub链接:https://github.com/longcw/RoIAlign.pytorch
当然现在PyTorch官方也提供了RoIAlign层,可以直接使用。如果直接使用官方的RoIAlign层,这没有这个问题了。

下面我们还是以使用了外部包的情况来说明。

尽管roi_align已经出现在了dist文件夹中,但我在运行中依然遇到了找不到roi_align-0.0.2-py3.6-win-amd64.egg的报错,我是通过以下方式来解决,让需要的包和依赖文件都被添加到dist文件夹中。

**核心还是根据报错信息添加对应的依赖文件。**这边只是一个示例

依然是需要修改.spec文件。

# -*- mode: python ; coding: utf-8 -*-

import sys
sys.setrecursionlimit(5000)
from os import path
site_packages = next(p for p in sys.path if 'site-packages' in p)
block_cipher = None

a = Analysis(['..\\main.py'],
             pathex=['E:\\release'],
             binaries=[],
             datas=[('..\\checkpoint.pth.tar','checkpoint.pth.tar') ,(path.join(site_packages,'roi_align-0.0.2-py3.6-win-amd64.egg'),'roi_align-0.0.2-py3.6-win-amd64.egg')],
             hiddenimports=['roi_align','crop_and_resize.py','crop_and_resize_cpu','scipy.special.cython_special'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)

解决自己的PC可以运行打包好的exe,别人PC却无法运行的问题

这个问题困扰了我好久。后来发现是问题出在缺少 Visual C++ Redistributable。解决方法是:

  1. 首先,请先确认 Windows 操作系统为 32 位还是 64 位(可参考该链接进行查询);

  2. 确定系统版本之后
    a) 32 位系统:"vc_redist.x86.exe”进行配置;
    b) 64 位系统:“vc_redist.x64.exe”进行配置;

微软官方有提供这两个安装包,网上搜索 一下也有很多。

将打包生成的文件夹转成一个单一exe

上面也说了,直接用-F可以时间打包成单一exe,但不推荐这样操作。
我这边使用的是Enigma Virtual Box,下载链接
在这里插入图片描述
免费版的即可。
运行Enigma Virtual Box
PyInstaller打包exe可执行文件详细教程_第2张图片在Enter Input File Name中选择dist中的exe文件main.exe,在Enter Output File Name中选择输出的路径和文件名,默认文件名是main_boxed.exe。
然后点击左下角Add…,选择Add Folder Recursive, 然后选择dist文件夹,确定即可。
PyInstaller打包exe可执行文件详细教程_第3张图片
需要进行压缩的话,选择右下角File Option然后勾选File Compress即可。
PyInstaller打包exe可执行文件详细教程_第4张图片等待压缩完成,完成后就得到一个单一exe了。

你可能感兴趣的:(实用工具,pyinstaller,pyqt5,pytorch)