1. 程式人生 > >Python 小技巧:如何實現作業系統相容性打包?

Python 小技巧:如何實現作業系統相容性打包?

有一個這樣的問題:現要用 setuptools 把一個專案打包成 whl 檔案,然後 pip install 在 Windows/Linux 兩種作業系統上,但是該專案中有一些依賴庫只有 Windows 上才有(例如 pywinauto、pywingui、pywinrm),那麼問題是,如何實現打包檔案的可相容性安裝? 從打包的角度,這個問題的關鍵還是看 setup.py 和 requirements.txt 檔案。 關於 Python 的包構建分發和 setup.py 的使用,這裡[有篇文章](https://mp.weixin.qq.com/s/mAoaIe_Sg3Vk2Sk_xZeI-w) 寫得很好,推薦閱讀。另外關於 Python 依賴庫的管理(requirements.txt),[這篇文章](https://mp.weixin.qq.com/s/bdeUDLihiuwZVmmquRYEug) 詳細比較了 pip、pipreqs、pigar、pip-tools 和 pipdeptree 等工具,也推薦一讀。 有一個比較笨的實現方法:維護兩份 requirements.txt 檔案,分別用來打包,然後分發給不同作業系統去使用。 但是這樣會有麻煩:維護兩份依賴檔案和兩種包檔案,本身就挺費勁的,而在生成過程中,每次還得對它們改名以作區分(注意包名有一定的規範約束,亂改的話,pip 可能識別不出),維護成本就很高。 其實,維護軟體包在不同作業系統的版本,並不少見。如果你曾留意過不同版本 Python 庫檔案的話,你會注意到很多庫都會按不同作業系統而分發不同的版本。例如,下面是同一版本號的 Numpy 在不同作業系統上的分發版([https://pypi.org/simple/numpy/](https://pypi.org/simple/numpy/)): ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gcx9hkpi5gj20iv09habb.jpg) 可以看出它根據 macos、linux 和 win 三類作業系統及其位數,分成了 5 個版本。維護這麼多版本,肯定是一件麻煩事,但是出現了這樣的結果,就意味著 Numpy 官方認為分發不同系統版本是利大於弊的,而且是有辦法實現的。 回到我們的問題,是否有必要像 Numpy 那樣設法打包成多個作業系統定製的包呢? 答案是否定的。主要的原因: - Numpy 這麼做是因為它是做科學計算的,為了提升效率,它把編譯好的 C 拓展檔案打包,從而不需要依賴環境上的 libxxx-devel 之類的庫。如果你編譯安裝過 Python,應該有印象需要安裝 zlib-devel、openssl-devel 和 libffi-devel 之類的系統依賴。但我們前面的問題比較簡單,並不是有不同的編譯依賴(系統級),而只是三方庫依賴不同(專案級)。 - 另一個主要的原因,Numpy 打包出的不同系統版本,並非簡簡單單地用 setuptools 之類的 Python 庫就能打包,而是要藉助標準的映象進行構建。例如,manylinux 版本的打包,參見 Github([https://github.com/pypa/manylinux](https://github.com/pypa/manylinux)),就需要使用官方提供的 Docker 映象。對於我們的問題,顯然不想做到這麼麻煩。 簡而言之,根據前面的分析,如果要實現作業系統相容的打包,維護多份依賴檔案、使用不同構建包的方法、維護多系統專用的包,方法可行,但並不是很適用。 如果沒有新的辦法,這不失為一種考慮,但是有沒有別的辦法了呢? 我曾被這個問題困擾過,但是沒有深入去研究解決,直到無意中在`loguru` 這個用來記錄日誌的庫的 setup.py 中看到: ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gcx9gu0oo7j20ln04l3yh.jpg) 再翻看大名鼎鼎的`requests` 庫檔案,發現還可以這樣寫: ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gcx9hw4cg2j20rl04jmx6.jpg) 兩個示例都是寫在 setup.py 檔案中,其實如果我們用 requirements.txt 檔案,也可以按這種格式寫,然後再讀取進來。 這種神奇的寫法是怎麼回事呢? 它的依據是 2015 年 11 月建立的 PEP-508(以及相關的但已被撤銷或拒絕了的 PEP-390、PEP-426、PEP-459、PEP-496),該 PEP 的主要意圖是增強 pip 等工具查詢軟體包的能力。 ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gcx9i5i67wj20u50hogn6.jpg) 比較重要的部分就是跟我們的問題相關的,即對作業系統作區分的標識,相關的有: ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gcx9ii3dhcj20vh0nj3zl.jpg) 有了這樣的擴充套件支援,在打包依賴項時,就可以解決相容性問題了。 例如 colorama 庫,如果我們只在 win32 系統才需要依賴,那麼在打包時就可以指定:“colorama>=0.3.4 ; sys_platform\=\='win32' ”;如果不需要限定 win32 系統,而是在 windows 環境都安裝,那麼可以寫成“colorama>=0.3.4 ; platform_system\=\='Windows' ”。 最終,我們解決了本文開頭的問題。這個問題可能比較小眾,解決起來也沒有什麼大文章可做,算是一個小小的 tips 分享給大