2020年12月11日 星期五

把Python打包成執行檔的Pyinstaller筆記

從接觸Python以來,一直都沒有很認真的處理執行檔的問題
因為都是寫自己在用的客制化工具,所以一直都沒有這種需求存在
不論是自己的電腦下,或是掛在樹莓派下
都有python環境的可以跑
但是要給別人用的話,在對方沒有python環境下
就確實需要編譯成執行檔了

python轉執行檔,用google下去查
目前大宗就是使用pyinstaller
使用上也很簡單
安裝完pyinstaller後,只要在python的環境下執行pyinstaller example.py
就可以在dist的子目錄得到example目錄與裡面的example.exe檔
想要單一個執行檔的話
下達pyinstaller --onefile example.py
之後在dist的子目錄裡,就可以得到exmaple.exe的單檔
然後問題就來啦

單純這樣執行下,我的單檔肥到破200MB,我的媽啊
其實不只單檔,執行目錄也是差不多
上網一查,原來是預設的執行方式可能會把python環境下所有的套件都引入
也就是像我的環境裡有裝tensorflow,那就會把tensorflow的dll一起包進來
那肥起來很正常
所以解決辦法呢?有兩種
一、創建一個只有必要的套件的單純環境,再執行Pyinstaller
二、包裝時把這些不要的套件全數排除
第一個辦法也不錯,但第二個辦法顯然更好
實際執行辦法有數種,先說初學者最常用的
使用pyinstaller後,會產生一個.spec的文字檔案
修改.spec檔案的excludes內容,加入想要排除的套件
然後重新執行pyinstaller時,使用spec檔而不是py檔
pyinstaller example.spec
這樣就可以留到容量縮簡的執行檔案

只是使用spec檔時要注意一件事
當執行.spec的時候,其它執行參數是沒有用的
例如我們先執行了pyinstaller example.py產生spec檔修改後
執行pyinstaller --onefile example.spec時
還是不會產生單一檔案,一樣是產生執行目錄與分散的檔案
除非把spec的內容改成下完--onefile的格式
因為實際上,spec檔就是所有執行參數最終的狀況
執行時就不會理會下參數的命令了
而前面有提到,排除不使用的模組有四種辦法
除了用pyinstaller產生spec修改外
還有直接使用pyi-makespec直接產生spec檔,然後修改後再執行
或是在pyinstaller執行時加入--exclude-module參數即可,像這樣
pyinstaller sample.py --exclude-module tensorflow --exclude-module tensorflow-base
嗯,要打好長啊,還是改spec檔比較簡單

從這裡進入了spec檔的範圍
如果想改什麼東西,大概還是進spec檔改比較快而且變化一致
不怕會不小心輸入錯參數,又要重跑編譯(包裝)一次
除了包裝成單檔,還有排除掉不用的模組之外
我有使用的部分還有二個,一個指定圖示(icon)給執行檔
一個是把額外的檔案給包進去使用

先講第一個,指定圖示的部分
使用pyinstaller包出來的,不管是不是單檔,執行檔的圖示都是預設pyinstaller給的圖示
要更換圖示很簡單,在spec裡找到exe = EXE(pyz,......)這邊
假如我們圖示檔的名稱是sample.ico
就加入icon = '\\path\\sample.ico'到EXE()裡面
這樣產生出來的執行檔就會是替換後的圖示了

第二個,在單檔中,加入額外的檔案
這個需求簡單地說就是程式執行時需要一些輔助的檔案
例如要讀取xml的設定檔,視窗的背景圖,選單的圖示等等
一般模式下當然是放入指定目錄中就好
可是當我需要這些將程式包成方便攜帶的單一檔案時
全部跟執行檔包成同一個檔案才是最佳方案
這個在網路上我有找到兩個辦法
一個是在a = Analysis()裡的datas = []加入想要的檔案路徑
可是我這個方法失敗
另一個辦法是在exe = EXE(pyz,......)這邊的[]裡
加入檔案名稱與路徑如下格式
[(檔案名稱, 檔案絕對路徑, 'DATA')]
會需要這個功能最主要當然是,要換圖示 XD
不管是我用ctypes借windows api寫出來的視窗介面
還是Tkinter寫出來的
程式上的圖示都是預設的
所以要讓程式看起來像個自制的程式
換上自家的圖示是有必要的

寫到這裡補充一下
我修改SPEC有用到的不只上面兩個
還有就是去console,也就是不顯示命令列視窗
這個最簡單,找到console=True改成False就行了

Pyinstaller學到這裡大概就很好用了
寫個程式打包給同事或其它人用應該不成大問題
有需要更多調整的話,大概會是大型專案才用得上
我這種永遠的菜鳥,應該沒什麼機會碰觸到
有遇到,再上stack overflow查吧 XD

沒有留言: