痞子衡嵌入式:串列埠除錯工具Jays-PyCOM誕生記(6)- 打包釋出(PyInstaller3.3.1)

痞子衡發表於2017-05-21

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是串列埠除錯工具Jays-PyCOM誕生之打包釋出

  經過上一篇軟體優化之後,Jays-PyCOM已經初長成,該到了出去歷練的時候了,只有經歷廣大群眾考驗過的軟體才是合格的軟體。痞子衡在開發Jays-PyCOM時本地安裝了很多軟體:Python、pySerial、wxPython等,這些軟體是Jays-PyCOM執行的基礎,但如果將來別人想用Jays-PyCOM,是不是也需要安裝這些軟體呢?答案當然不是,如果是的話,Jays-PyCOM基本就沒人願意使用了。為了讓別人能夠不需要特殊環境便能執行Jays-PyCOM,我們需要將Jays-PyCOM打包成獨立可執行檔案,此時我們需要藉助專門的Python打包工具,本篇是這個系列的最後一篇,痞子衡為大家講如何使用打包工具打包Jays-PyCOM去釋出。

一、PyInstaller簡介

  Python打包工具有很多,如py2exe、cx_Freeze、PyInstaller,其中痞子衡首推PyInstaller。PyInstaller誕生於2005年,經過這麼多年的發展,其版本已經更新到v3.x,其主頁如下:

PyInstaller官方主頁: http://www.pyinstaller.org/
PyInstaller的github主頁: https://github.com/pyinstaller/pyinstaller

  在使用PyInstaller進行打包工作之前,首先需要確定你的Python應用程式所呼叫的所有第三方庫是不是在PyInstaller支援列表裡,這個主頁顯示了PyInstaller支援的所有第三方庫: https://github.com/pyinstaller/pyinstaller/wiki/Supported-Packages,基本上常用的第三方庫都在列表裡,比如Django、numpy、PyGame、PyOpenGL、PyQt、PyWin32等。
  PyInstaller的使用非常簡單,可先閱讀一遍官方文件。對於Jays-PyCOM的打包,我們只需要掌握-F、-w、-i三個命令選項以及.spec檔案使用就可以了。

PyInstaller官方文件主頁: https://readthedocs.org/projects/pyinstaller/
PyInstaller 3.3.1命令上手: https://pyinstaller.readthedocs.io/en/v3.3.1/usage.html#options
PyInstaller 3.3.1 spec檔案: https://pyinstaller.readthedocs.io/en/v3.3.1/spec-files.html#using-spec-files

二、將JaysPyCOM打包

  安裝好PyInstaller工具便可以開始打包Jays-PyCOM軟體了,讓我們開始吧,開始之前先介紹下Jays-PyCOM資料夾目錄結構,結構目錄是很簡單的,只有三個.py原始檔和三張圖片,這構成了Jays-PyCOM軟體的全部原始檔。

\Jays-PyCOM
           \.idea                          --放置PyCharm工程檔案
           \bin                            --放置工程釋出的exe檔案
           \gui                            --放置工程GUI設計檔案
                  \Jays-PyCOM.fbp            --wxFormBuilder工程檔案
           \img                            --放置工程引用圖片檔案
                  \led_black.png
                  \led_green.png
                  \logo_merge.jpg
           \src                            --放置工程原始碼檔案
                  \formatter.py    --工程linker檔案
                  \main.py         --板級相關的原始檔(比如pinout,clock等)
                  \win.py          --wxPython視窗原始檔(wxFormBuilder生成)

2.1 打包準備

  由於Jays-PyCOM應用程式總共只有6個原始檔,並且都已經準備就緒,Jays-PyCOM依賴的pySerial、wxPython庫也都在PyInstaller支援的列表裡,所以唯一剩下的準備工作便是製作Jays-PyCOM的圖示檔案。
  要製作圖示檔案,首先你得有一張圖片檔案,痞子衡將pySerial的logo擷取了部分用作Jays-PyCOM的圖示,有了圖片,可以使用這個網站 https://converticon.com/ 將其轉換成圖示檔案(.ico),圖示檔案製作好之後將其放在 \Jays-PyCOM\img\目錄下:

\Jays-PyCOM
           \img                            --放置工程引用圖片檔案
                  \Jays-PyCOM.png
                  \Jays-PyCOM.ico

2.2 開始打包

  準備工作就緒,可以開始打包了,在使用PyInstaller打包前必須明白一點的是,PyInstaller僅能將.py格式的原始檔以及其所呼叫的相關Python第三方原始檔庫打包進最終的.exe檔案,如果你的應用程式會用到圖片等多媒體檔案,這些多媒體檔案並不能被打包,後續exe在使用時,這些多媒體檔案必須一同在場,並且還要保證與打包/開發時的相對路徑是一致的
  痞子衡使用的是如下命令格式打包Jays-PyCOM: pystaller -F -w [src1.py] [src2.py]... -i [pic.ico],解釋一下這個命令組合,-F的意思是將應用程式打包成單個可執行檔案(與其對立的命令是-D,打包成多檔案放在一個資料夾),-w表明要打包成視窗型(與其對立的命令是-c,控制檯型),[src1.py][src2.py][...]為你自己建立的應用程式原始檔(src1.py必須是含__main__的主函式檔案),-i指定圖示檔案。

PS D:\my_git_repo\JaysPyCOM\bin> pyinstaller -F -w ..\src\main.py ..\src\formatter.py ..\src\win.py -i ..\img\Jays-PyCOM.ico

223 INFO: PyInstaller: 3.3.1
225 INFO: Python: 2.7.14
227 INFO: Platform: Windows-10-10.0.15063
230 INFO: wrote D:\my_git_repo\Jays-PyCOM\bin\main.spec
233 INFO: UPX is not available.
237 INFO: Extending PYTHONPATH with paths
['D:\\my_git_repo\\JaysPyCOM\\bin',
 'D:\\my_git_repo\\JaysPyCOM\\src',
 'D:\\my_git_repo\\JaysPyCOM\\src',
 'D:\\my_git_repo\\JaysPyCOM\\src']
238 INFO: checking Analysis
240 INFO: Building Analysis because out00-Analysis.toc is non existent
240 INFO: Initializing module dependency graph...
246 INFO: Initializing module graph hooks...
323 INFO: running Analysis out00-Analysis.toc
342 INFO: Adding Microsoft.VC90.CRT to dependent assemblies of final executable
  required by c:\tools_mcu\python27\python.exe
5611 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.1_none_3da38fdebd0e6822.manifest
5615 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.6161_none_acd388d7e1d8689f.manifest
5621 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9279_none_acd3d86fe1d846c4.manifest
5825 INFO: Searching for assembly amd64_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.9279_none ...
5826 INFO: Found manifest C:\WINDOWS\WinSxS\Manifests\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9279_none_08e667efa83ba076.manifest
5828 INFO: Searching for file msvcr90.dll
5829 INFO: Found file C:\WINDOWS\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9279_none_08e667efa83ba076\msvcr90.dll
5830 INFO: Searching for file msvcp90.dll
5832 INFO: Found file C:\WINDOWS\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9279_none_08e667efa83ba076\msvcp90.dll
5833 INFO: Searching for file msvcm90.dll
5835 INFO: Found file C:\WINDOWS\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9279_none_08e667efa83ba076\msvcm90.dll
6032 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.1_none_3da38fdebd0e6822.manifest
6033 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.6161_none_acd388d7e1d8689f.manifest
6034 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9279_none_acd3d86fe1d846c4.manifest
6037 INFO: Adding redirect Microsoft.VC90.CRT version (9, 0, 21022, 8) -> (9, 0, 30729, 9279)
6175 INFO: Caching module hooks...
6180 INFO: Analyzing D:\my_git_repo\Jays-PyCOM\src\main.py
8021 INFO: Analyzing D:\my_git_repo\Jays-PyCOM\src\formatter.py
8024 INFO: Analyzing D:\my_git_repo\Jays-PyCOM\src\win.py
8040 INFO: Loading module hooks...
8040 INFO: Loading module hook "hook-wx.xrc.py"...
8046 INFO: Loading module hook "hook-encodings.py"...
8750 INFO: Looking for ctypes DLLs
8758 INFO: Analyzing run-time hooks ...
8766 INFO: Looking for dynamic libraries
9258 INFO: Looking for eggs
9258 INFO: Using Python library C:\WINDOWS\system32\python27.dll
9260 INFO: Found binding redirects:
[BindingRedirect(name=u'Microsoft.VC90.CRT', language=None, arch=u'amd64', oldVersion=(9, 0, 21022, 8), newVersion=(9, 0, 30729, 9279), publicKeyToken=u'1fc8b3b9a1e18e3b')]
9264 INFO: Warnings written to D:\my_git_repo\JaysPyCOM\bin\build\jayspycom_main\warnjayspycom_main.txt
9287 INFO: Graph cross-reference written to D:\my_git_repo\JaysPyCOM\bin\build\jayspycom_main\xref-jayspycom_main.html
9329 INFO: checking PYZ
9329 INFO: Building PYZ because out00-PYZ.toc is non existent
9330 INFO: Building PYZ (ZlibArchive) D:\my_git_repo\JaysPyCOM\bin\build\main\out00-PYZ.pyz
9608 INFO: Building PYZ (ZlibArchive) D:\my_git_repo\JaysPyCOM\bin\build\main\out00-PYZ.pyz completed successfully.
9648 INFO: checking PKG
9649 INFO: Building PKG because out00-PKG.toc is non existent
9651 INFO: Building PKG (CArchive) out00-PKG.pkg
9796 INFO: Redirecting Microsoft.VC90.CRT version (9, 0, 21022, 8) -> (9, 0, 30729, 9279)
14667 INFO: Building PKG (CArchive) out00-PKG.pkg completed successfully.
14674 INFO: Bootloader c:\tools_mcu\python27\lib\site-packages\PyInstaller\bootloader\Windows-64bit\runw.exe
14674 INFO: checking EXE
14677 INFO: Building EXE because out00-EXE.toc is non existent
14678 INFO: Building EXE from out00-EXE.toc
14695 INFO: SRCPATH [('..\\img\\jayspycom.ico', None)]
14697 INFO: Updating icons from ['..\\img\\Jays-PyCOM.ico'] to c:\users\nxa07314\appdata\local\temp\1\tmpcvu1zy
14698 INFO: Writing RT_GROUP_ICON 0 resource with 20 bytes
14698 INFO: Writing RT_ICON 1 resource with 4264 bytes
14707 INFO: Appending archive to EXE D:\my_git_repo\Jays-PyCOM\bin\dist\main.exe
14724 INFO: Building EXE from out00-EXE.toc completed successfully.

  打包命令成功執行之後,便可以在\Jays-PyCOM\bin目錄下看到如下生成的檔案:

\JaysPyCOM
           \bin                            --放置工程原始碼檔案
                  \build\                    --
                  \dist\main.exe             --可執行exe檔案
                  \main.spec                 --spec檔案

  其中build資料夾存放的是PyInstaller在打包過程中生成的除錯資訊檔案,dist資料夾下面的main.exe便是我們要的最終的可執行檔案,main.spec是PyInstaller自動生成的命令解釋檔案,其實你在命令列裡輸入的命令首先被翻譯放到.spec檔案裡,然後PyInstaller主要是根據.spec檔案來打包的,不信你可以試著用pyinstaller main.spec命令重新再打包一次,得到的結果是一樣的。下面是.spec檔案裡的內容,如果你對.spec檔案瞭解,當然也可以自己建立.spec檔案來進行打包。

# -*- mode: python -*-

block_cipher = None


a = Analysis(['main.py', 'formatter.py', 'win.py'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Jays-PyCOM',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=False , icon='..\\img\\Jays-PyCOM.ico')

  main.exe可執行檔案已經生成好了,讓我們試著開啟使用一下,直接在\Jays-PyCOM\bin\dist\目錄下開啟這個檔案發現報瞭如下錯誤,看起來是找不到圖片路徑,這是怎麼回事?痞子衡其實在前面已經提到過,需要保證資料夾內圖片相對路徑與打包時相對路徑一致,試著將main.exe放到\Jays-PyCOM\bin\目錄下再開啟看是不是正常了,因為這時候相對路徑是一致的。大功告成了,最後將main.exe重新命名為Jays-PyCOM.exe。

痞子衡嵌入式:串列埠除錯工具Jays-PyCOM誕生記(6)- 打包釋出(PyInstaller3.3.1)

番外篇

  正文中講了,最終的Jays-PyCOM.exe必須配合Jays-PyCOM資料夾(主要是\img裡的圖片)一起使用,並且不能任意移動Jays-PyCOM.exe在Jays-PyCOM資料夾中位置,看起來這個Jays-PyCOM.exe還是有一些使用限制(當然你可以建立Jays-PyCOM.exe的快捷方式到桌面,你可以任意移動這個快捷方式,這算是一個workaround),能不能打破這個限制?只要一個Jays-PyCOM.exe檔案即可,並且放到任意目錄下都能執行?答案是有,可以參看這篇文章的思路 pyinstaller打包——圖片資源無法顯示問題,思路大概原理是事先將圖片編碼存到.py原始檔裡,這樣在打包時便可將這個圖片資料.py原始檔直接打包進Jays-PyCOM.exe,後續Jays-PyCOM.exe在執行時首先將圖片資料解碼出來並在本地儲存為臨時圖片,這樣Jays-PyCOM.exe啟動便可完成圖片載入,等Jays-PyCOM.exe圖片載入完成之後可以刪除臨時圖片檔案。思路有了,小夥伴趕緊動手試一試,這算是痞子衡在這個系列最後一課留給大家的一個課後作業。

  至此,串列埠除錯工具Jays-PyCOM誕生之打包釋出痞子衡便介紹完畢了,掌聲在哪裡~~~

相關文章