1. 程式人生 > >python 2.7.x to exe

python 2.7.x to exe

Intro

為了更好的部署python project,在windows環境下比較合適的方式就是編譯生成相應的exe可執行檔案,並且不依賴與環境。好處自不必說,一者不想專案的原始碼隨意洩露,另一方面可考慮到部署的方便性,不需要安裝相應的python執行環境和許多packages確實有很大的誘惑。於是乎,開始了痛苦,艱辛的探索之旅。

開發環境

專案 說明
作業系統 win10 x64
python版本 2.7.x
python包管理器

探索之路

  • Py2exe: 最先找到的嘗試方案,但在安裝過程中發現需要python 3.x 的版本,直接放棄了,大家有嘗試過的可以留言是否好用哦.

  • Cython + MinGW:之前嘗試過用cython編寫python功能模組,通過cython編譯器編譯成相應的pyd模組,然後在普通的py檔案中就可以直接呼叫, eg. example.pyd:

## import cython .pyd file
cimport example

cython在編譯時會生成相關的.c檔案,可以通過linux下的gcc編譯成可執行檔案,在windows下,則是mingw,早前為了能使編譯後的exe能夠通用在32位和64位的機器上,所以下載了mingw 32位的版本。從官網下載安裝後就可以在命令列中使用gcc命令。
但在常識後發現,gcc想要編譯完整的專案需要配置大量引數,動態庫等等,解決各種包,庫的依賴,eg.

gcc <file.c> -I <include path> -L<directory_containing_libpython> -l<name_of_libpython_without_lib_on_the_front>-lpython27  -o <output file path>

總的來說,需要對c和python相關包庫有一定了解,對於筆者這種懶人來說,還是後期有空閒時間再研究。

  • Pyinstaller: 最終的解決方案,按照官網上說的:

PyInstaller is a program that freezes (packages) Python programs into stand-alone executables, under Windows, Linux, Mac OS X, FreeBSD, Solaris and AIX. Its main advantages over similar tools are that PyInstaller works with Python 2.7 and 3.3—3.5, it builds smaller executables thanks to transparent compression, it is fully multi-platform, and use the OS support to load the dynamic libraries, thus ensuring full compatibility.

2.x,3.x全相容,完美;windows,linux,macos全相容,完美;自動處理包的依賴問題,完美。但只有用過才知道,其本身存在著各種缺陷,一句話:需要找到適合自身方案的才是最好的。

解決方案

pyinstaller最終可以實現python程式碼轉換成exe的功能,

## 直接在命令列中呼叫pyinstaller
> pyinstaller example.py

它會自動載入很多類庫,有些是你需要的,有些是你不需要的,最終會導致結果檔案很大,所以說pyinstaller適合於大型專案的轉換,對於小型的模組可能用gcc或是visual studio編譯更方便。另外,編譯過程中可能遇到各種問題,很難去debug,除了藉助google還沒找到更好的辦法。下面就列舉下在呼叫中載入不同的包庫是遇到的問題和解決方案:

pyinstaller 使用FAQ

  1. No module Named **型別
    答:在import pymssql,sqlalchemy.sql.default_comparator中遇到,解決方法是在主檔案中import 這些包,例如_mssql,當然如果本身沒安裝的話可以通過pip及類似的包管理器安裝。
import pymssql
import _mssql
import sqlalchemy.sql.default_comparator
  1. geos.dll型別
    答:在使用shapely包時遇到,其報錯資訊如下:

Traceback (most recent call last):
File “TRobot.py”, line 11, in
File “c:\users\edward\appdata\local\temp\pip-build-gsgzsn\pyinstaller\PyInstaller\loader\pyimod03_importers.py”, line 389, in load_module
File “site-packages\shapely\geometry__init__.py”, line 4, in
File “c:\users\edward\appdata\local\temp\pip-build-gsgzsn\pyinstaller\PyInstaller\loader\pyimod03_importers.py”, line 389, in load_module
File “site-packages\shapely\geometry\base.py”, line 9, in
File “c:\users\edward\appdata\local\temp\pip-build-gsgzsn\pyinstaller\PyInstaller\loader\pyimod03_importers.py”, line 389, in load_module
File “site-packages\shapely\coords.py”, line 8, in
File “c:\users\edward\appdata\local\temp\pip-build-gsgzsn\pyinstaller\PyInstaller\loader\pyimod03_importers.py”, line 389, in load_module
File “site-packages\shapely\geos.py”, line 76, in
File “site-packages\PyInstaller\loader\pyiboot01_bootstrap.py”, line 131, in init
File “ctypes__init__.py”, line 362, in init
WindowsError: [Error 126]
Failed to execute script TRobot

這時的問題是shapely這個包需要呼叫兩個dll動態連線庫,但是系統沒找到,也就是pyinstaller在編譯時沒有把他們載入進去,這兩個庫的名字是:geos_c.dll,geos.dll。
儲存的位置,以筆者使用anaconda為例:

D:\anaconda64\Library\bin\geos_c.dll

在anaconda根目錄下的Library\bin子目錄中,解決方法是將這兩個dll檔案複製到pyinstaller的輸出目錄dist中即可(預設在當前目錄下)。

mv geos_c.dll,geos.dll <path to your dist\example> 

PS:pyinstaller有兩種輸出exe的方式,一種是

## 將exe儲存成目錄Directory,也就是這個目錄中下有example.exe,預設是這種型別
> pyinstaller -D example.py

另一種是:

## 將exe儲存成單個檔案File,也就是在dist下有example.exe
> pyinstaller -F example.py

因此如果要想實現上述的移動dll解決方案就必須採取第一種轉換方式,儲存成目錄,再將dll連線庫放到這個目錄中。

後記

Hew a stone of hope from the mountain of despire, you will life a splendid one
-俞敏洪
探索過程越艱辛,得到時就越幸福,與君共勉!