通常來說,Python 程式包有兩種型別的發行版,分別是原始碼發行版和二進位制(構建)發行版。
原始碼發行版是最簡單的,也是最不依賴於平台的,對於純 Python 包,無需動腦選擇它就行,這種發行版只包含 Python 原始碼,具有高度的可移植性。
但當包中引入了用其他語言(例如 C 語言)編寫的一些擴充套件,如果包使用者的環境中有合適的開發工具鏈(主要包括編譯器和正確的 C 標頭檔案)的話,那麼原始碼發行版也是可行的。相比較而言,二進位制發行版的格式可能更適合,因為它可以為特定平台提供已經構建好的擴充套件。
sdist發行版
sdist 命令是最簡單的命令,它建立一棵分發樹,其中複製了執行一個包所需要的全部內容,這棵樹被歸檔到一個或多個存檔檔案中(通常只建立一個 tar 檔案),這個存檔基本上是原始碼樹的副本。
這個命令是從目標系統獨立地分發一個包的最簡單方法,它將建立一個 dist 資料夾,裡面包含可被分發的存檔。為了能夠使用它,必須向 setup 傳遞一個額外引數以提供版本號,如果沒有提供 version 值,那它預設為 version = 0.0.0,程式碼如下:
from setuptools import setup
setup(
name='acme.sql',
version='0.1.1'
)
這個版本號在升級安裝時非常有用,因為每次發布包時版本號都會增加,這樣目標系統就知道它發生了變化。
我們執行帶有這個額外引數的 sdist 命令,程式碼如下:
$ python setup.py sdist
running sdist
...
creating dist
tar -cf dist/acme.sql-0.1.1.tar acme.sql-0.1.1
gzip -f9 dist/acme.sql-0.1.1.tar
removing 'acme.sql-0.1.1' (and everything under it)
$ ls dist/
acme.sql-0.1.1.tar.gz
在 Windows 中,存檔其實就是一個ZIP文件。
版本被用於標記存檔名稱,這個存檔可以在任何擁有 Python 的系統上分發並安裝。在 sdist 發行版中,如果包裡面包含 C 庫或擴充套件,那麼目標系統將負責編譯它們。
這在基於 Linux 的系統或 Mac OS 中很常見,因為這些系統通常都會提供編譯器,但在 Windows 下卻並不常見。因此,如果一個包打算在多個平台中執行,那麼分發時應該同時提供預構建的發行版。
bdist和wheels發行版
為了能夠分發預構建的發行版,distutils 提供了 build 命令,可以通過 4 個步驟來編譯包,分別是:
-
build_py:通過位元組編譯並將其複製到構建資料夾中,來構建純 Python 模組。
-
build_clib:如果包中包含任何 C 庫,它會利用 C 編譯器在構建資料夾中建立一個靜態庫來構建C庫。
-
build_ext:構建 C 擴充套件,並像 build_clib 一樣將結果放在構建資料夾中。
-
build_scripts:構建被標記為指令碼的模組。如果第一行被設為 !# 的話,它還會修改直譯器路徑並修改檔案模式使其變為可執行檔案。
上面每個步驟都是可以被單獨呼叫的命令,編譯過程的結果是構建一個資料夾,裡面包含要安裝的包所需要的全部內容。
需要注意的是,distutils 包中還沒有提供交叉編譯器的選項,也就是說,這些命令的結果總是針對構建時所使用的作業系統。
如果必須建立一些 C 擴充套件,構建過程將使用系統編譯器和 Python 標頭檔案(Python.h)。Python 從原始碼構建完成之後這個包含(include)檔案就是可用的了。對於打包的發行版,可能需要針對系統發行版的額外包,至少在流行的 Linux 發行版中,它通常被命名為 python-dev,其包含構建 Python 擴充套件所有必要的標頭檔案。
所使用的 C 編譯器是系統編譯器,對於基於 Linux 系統或 Mac OS X 而言,它分別是 gcc 或 clang。對於 Windows 而言,可以使用 Microsoft Visual C++,也可以使用開源專案 MinGW,可以在 distutils 中進行相應的設定。
bdist 命令使用 build 命令來構建二進位制發行版。它呼叫 build 和所有依賴的命令,然後用和 sdist 相同的方式建立一份存檔。
我們在 Mac OS X 系統中為 acme.sql 建立一個二進位制發行版,如下所示:
$ python setup.py bdist
running bdist
running bdist_dumb
running build
...
running insta1l_scripts
tar -cf dist/acme.sql-0.1.1.macosx-10.3-fat.tar
gzip -f9 acme.sql-0.1.1.macosx-10.3-fat.tar
removing 'build/bdist.macosx-10.3-fat/dumb' (and everything under it)
$ ls dist/
acme.sql-0.1.1.macosx-10.3-fat.tar.gz acme.sql-0.1.1.tar.gz
注意,新建立的存檔名稱中包含系統名稱及其發行版本(Mac OS X 10.3)。
在 Windows 中,呼叫相同的命令將會建立一個特定的發行版存檔,如下所示:
C:acme.sql> python.exe setup.py bdist
...
C:acme.sql> dir dist
25/02/2008 08:18 <DIR> .
25/02/2008 08:18 <DIR> ..
25/02/2008 08:24 16 055 acme.sql-0.1.Win32.zip
1 File(s) 16 055 bytes
2 Dir(s) 22 239 752 192 bytes free
如果一個包裡包含 C 程式碼,那麼除了原始碼發行版之外,發布盡可能多的不同的二進位制發行版也很重要。至少對於那些沒存安裝 C 編譯器的人是很重要的。
二進位制版本中包含一棵可以汽接複製到 Python 樹中的樹,它主要包含一個資料夾,將被複製到 Python 的 site-packages 資料夾中。同時,它還可能包含快取位元組碼檔案(在 Python 2.x 中是 *.pyc 檔案,在 Python 3.x 中是 __pycache__/*.pyc)。
另一種構建發行版是 wheel 包提供的“wheel”,安裝完 wheel 後(例如使用 pip),它會向 distutils 中新增一個新的 bdist_wheel 命令。wheel 允許建立特定平台的發行版(目前僅適用於 Windows 和 Mac OS X),作為普通 bdist 發行版的替代。
設計 wheel 是為了替代早先 setuptools 引入的另一種 egg 版本,egg 現在己經過時了,所以這裡不再詳細介紹它。
使用 wheel 的優點相當多,在 Python Wheels 中提到的優點如下所示:
-
更快速地安裝純 Python 包和本地 C 擴充套件包;
-
避免安裝任意程式碼執行(避免 setup.py);
-
安裝 C 擴充套件不需要 Windows 或 OS X 上的編譯器。
-
允許更好的快取,用於測試和持續整合。
-
建立 .pyc 檔案作為安裝的一部分,以確保它們匹配所使用的 Python 直譯器;
-
在跨平台和跨機器上更一致的安裝。
根據 PyPA 的推薦,wheel 應該成為預設的分發格式。但 Linux 平台特定的 wheel 還不可用,因此如果必須分發帶有 C 擴充套件的包,那麼需要為 Linux 使用者建立 sdist 發行版。