Python打包工具

1 Python打包工具

目前在windows平臺上將Python程序打包成exe文件主要有三個工具。html

今天將一個Tkinter寫的界面程序打包成exe文件,三個工具都試了一遍,感受PyInstaller會比較好用一些。python

2 py2exe

2.1 下載安裝

從這裏https://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/ 選擇python版本和計算機位數對應的exe文件,雙擊便可安裝。windows

2.2 啓動腳本

寫一個setup_py2exe.py文件app

from distutils.core import setup
import py2exe
options = {'py2exe': {'compressed': 1,
                      'optimize': 2,
                      'bundle_files': 1, }}
setup(name='App',
      author='kinegratii',
      version='1.0.0',
      options=options,
      windows=[{"script": "app.py"}],
      zipfile=None
      )

2.3 命令

執行python setup_py2exe.py py2exe便可,dist目錄就是最後生成的結果。ide

2.4 Q&A

import py2exe函數

import py2exe這個語句要保留,由於用PyCharm自動格式化的時候總會把這個語句優化掉。工具

UnicodeDecodeError異常優化

以前加了from __future__ import unicode_literals這個語句,會報UnicodeDecodeError: 'utf8' codec can't decode byte 0xd1 in position 3: invalid continuation byteui

lxml庫spa

程序報的異常是ImportError: No module named lxml._elementpath,但按照網上的說法加了includes參數能夠解決。

options={
    'py2exe': {
        'includes': ['lxml.etree', 'lxml._elementpath', 'gzip'],
    }
}

TypeError: expected string or buffer

這個異常是docx這個庫出現的。找了好久尚未什麼頭緒。

3 cx_freeze

3.1 pip安裝

執行pip命令便可安裝

pip install cx_Freeze

3.2 啓動腳本

setup_cx.py文件以下

from __future__ import unicode_literals
import sys
from cx_Freeze import setup, Executable
base = None
if sys.platform == "win32":
    base = "Win32GUI"
includeFiles = [
    (r"D:\py\tcl\tcl8.5", "tcl"),
    (r"D:\py\tcl\tk8.5", "tk")
]
setup(
    name="App",
    version="1.0",
    description="A demo app",
    options={"build_exe": {"include_files": includeFiles, }},
    executables=[Executable("app.py", base=base, includes=['lxml', 'lxml.tree', 'lxml._namepath'])]
)

3.3 命令

執行命令python setup_cx.py build,dist下的exe.開頭的文件夾(名字跟具體環境有關,好比個人是exe.win32-2.7)就是最後的生成的文件夾。

3.4 Q&A

lxml

也須要明確包含lxml._elementpath

docx

也出現了和py2exe同樣的異常。

4 PyInstaller

4.1 pip安裝

執行pip安裝

pip install pyinstaller
```

安裝成功後在python的目錄下\Scripts文件夾多出pyinstaller.exe、pyinstaller.exe.manifest、pyinstaller-script.py等幾個文件。

### 4.2 命令方式構建

把Scripts目錄加到系統的環境變量中,cd到腳本所在的目錄,而後執行下面的命令。

```
pyinstaller app.py -F -w --clean
```

app.py 腳本文件

幾個選項含義

- -F 打包爲單一文件,和打包爲一個文件夾相對,默認爲後者
- -w 窗口程序,與控制檯相對
- --clean 每次清理中間產生的構建文件

生成的相關文件包括

- app.spec 配置文件
- build文件夾 構建中產生的中間文件
- dist/app文件夾 這裏的文件都是運行所須要的

### 4.3 啓動腳本方式

命令行帶太多參數的話,每次都要輸入,比較麻煩,能夠通通寫在一個py腳本中。

PyInstaller也是一個標準的Python包,提供了`PyInstaller.main.run`這個方法。

4.2節中等效的python腳本以下

```
if __name__ == '__main__':
    from PyInstaller.main import run
    params=[app.py', '-F', '-w', '--clean']
    run(params)
```

用Python解釋器執行這個腳本就能夠了。

### 4.4 Q&A

**lxml**

能夠解決lxml包含的問題,無需明確指定

**調試**

因爲用了沒有控制檯的-w方式,若是程序啓動有錯的話,只會彈出app return -1的對話框,沒有具體異常信息。能夠先去掉-w,用控制檯進行調試,全部的異常和程序中的print函數就顯示在控制檯上,方便調試。

**單exe資源文件路徑問題**

這個問題應該只要是最後打包成單個exe都會出現的問題。描述以下

最後打包的文件結構以下

```
- XxxApp
    - app.exe
    - data
        - wpa.db
```

程序中用下面語句引用wpa.db文件,會出現文件打不開的狀況

```
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
DB_FILE = os.path.join(BASE_DIR,'data', 'wpa.db')
```
調試打印出`BASE_DIR`,發現路徑不是XxxApp,而是在用戶目錄下的某一個位置,相似以下

```
c:\Users\kinegratii\AppData'Local\Temp\_MEI11~1\dadta\wpa.db
```

這是由於**在單文件模式中運行程序的時候先將文件解壓到sys._MEIPASS指向的目錄下,因此引用資源文件就須要添加os.path.join(sys._MEIPASS,filename)**,

第一種方法,具體判斷程序當前模式。

```
  if getattr(sys, 'frozen', False):
        BASE_DIR = sys._MEIPASS
    else:
        BASE_DIR = os.path.dirname(__file__)
```

第二種,就是將`__file__`改成sys.args[0],即

```
BASE_DIR = os.path.abspath(os.path.dirname(sys.argv[0]))
```

這樣打印的路徑就是正確的了,緣由在於`__file__`和`sys.args[0]`有點區別。

> `__file__` is the name of the current file, which may be different from the main script if you are inside a module or if you start a script using execfile() rather than by invoking python scriptname.py.  `__file__` is generally your safer bet.

來自 http://stackoverflow.com/a/5851608

**icon圖標沒法顯示問題**

使用icon選項便可添加圖標,但有時候發現資源管理器的圖標能夠顯示,但運行程序後任務欄上的圖標卻沒法顯示。關於這個問題 。

> 在不一樣狀況下(好比資源管理器文件列表前面的圖標、桌面、開始菜單等)須要不同尺寸的圖標。若是尺寸不合適的話,可能出現有的地方顯示正確有的顯示不正確的狀況。最後幾個地方都要檢查一遍。

解決方案

> 應該準備四張不一樣尺寸(具體尺寸參見 http://stackoverflow.com/questions/3236115/which-icon-sizes-should-my-windows-applications-icon-include )的png文件
用png2icon腳本把它們合成一張icon圖標文件便可

## 5 參考資料

- py2exe lxml error http://stackoverflow.com/a/5309733
- Creating an Executable from a Python Script | Matt Borgerson
https://mborgerson.com/creating-an-executable-from-a-python-script
- pyinstaller打包pyqt文件 - dcb3688 - 博客園
http://www.cnblogs.com/dcb3688/p/4211390.html
- 使用pyinstaller打包python程序 - 魏哲的空間
https://blog.weizhe.net/?p=412
相關文章
相關標籤/搜索