從一件小事看Python
一件關(guān)于Python開(kāi)發(fā)的小事,折騰了一天還是失敗了,是Python難搞還是有別的原因?且看……
近日用webpy開(kāi)發(fā)了一個(gè)小Web應(yīng)用,用到了PIL(一個(gè)圖形庫(kù))。在把它部署到正式的Linux服務(wù)器之前,我覺(jué)得有必要在Windows上先“仿真”測(cè)試一下,用Windows+Apache+WSGI+webpy+PIL環(huán)境測(cè)試一下這個(gè)Web應(yīng)用。但不幸的是,這個(gè)測(cè)試環(huán)境最終沒(méi)有搭建成功。
我的Windows開(kāi)發(fā)環(huán)境下有Python2.5/2.6/2.7三個(gè)版本。我一直使用2.5作為默認(rèn)的Python版本。那個(gè)Web應(yīng)用也是在2.5下開(kāi)發(fā)的。而且我的Linux服務(wù)器上也用2.5。
我遇到的***個(gè)問(wèn)題是:Windows上WSGI只有兩個(gè)官方binary,分別對(duì)應(yīng)Python2.6和2.7,沒(méi)有2.5。對(duì)我來(lái)說(shuō),如果要維持一貫的Python環(huán)境(包括服務(wù)器部署環(huán)境),就必須自己編譯WSGI的Python2.5版本。這件事非常麻煩:首先是必須使用跟Python2.5的binary相同的編譯器——VC2003(這種古董我都沒(méi)地方去找,我機(jī)器上只有VC2010)。其次還要找到所有相關(guān)的(且正確的)C鏈接庫(kù),如libhttpd.lib等。如果我使用官方的WSGI binary,我只能把環(huán)境轉(zhuǎn)換到高版本的Python,雖然這仍然意味著不少工作——包括服務(wù)器環(huán)境的整體升級(jí)等等,但我考慮再三,決定還是升級(jí)Python。
但我馬上就遇到了第二個(gè)問(wèn)題:PIL庫(kù)的官方binary在Python2.7上不能工作!在加載_imagingft時(shí)會(huì)報(bào)告錯(cuò)誤“ImportError: DLL load failed”。用depends工具檢查發(fā)現(xiàn)缺少M(fèi)SVCR90.dll,就到MS的網(wǎng)站上下載了VC++ 2008的 Redistributable Package。但安裝后問(wèn)題依舊。抓狂!其后一度研究了自行編譯PIL,發(fā)覺(jué)這事兒也不簡(jiǎn)單,遂放棄,繼續(xù)找問(wèn)題原因。***還真讓我找著了https://bitbucket.org/effbot/pil-117/issue/1/windows-build-of-_imagingft-module-fails-to。簡(jiǎn)單說(shuō)就是:PIL官方binary編譯有問(wèn)題:_imagingft.pyd(動(dòng)態(tài)鏈接庫(kù))鏈接的是MSVCR90.dll的DEBUG版本(話說(shuō)這個(gè)問(wèn)題存在一年以上了,官方就不管管嗎)!所以即使安裝了VC2008的Redistributable Package也沒(méi)用(DEBUG版本不在發(fā)行版中)!解決辦法就是用二進(jìn)制編輯器修改嵌在DLL里的manifest(這個(gè)辦法我覺(jué)得較危險(xiǎn)),或者用mt.exe工具從DLL導(dǎo)出manifest,修改后再導(dǎo)入DLL。mt.exe的用法可參考MSDN文檔http://msdn.microsoft.com/en-us/library/aa375649(v=vs.85).aspx。
解決了這兩個(gè)問(wèn)題,大半天過(guò)去了。就在我以為萬(wàn)事俱備的時(shí)候,第三個(gè)問(wèn)題出現(xiàn)了,并且一劍封喉:在Apache的WSGI環(huán)境下PIL還是可恥的加載失敗了——在import _imaging的時(shí)候,報(bào)告“ImportError: DLL load failed”。我再次抓狂了:我打開(kāi)Python控制臺(tái),直接import imaging,沒(méi)有問(wèn)題。那么問(wèn)題再哪兒?從日志上看,Python及其庫(kù)的路徑是沒(méi)問(wèn)題的。那么問(wèn)題再哪兒?問(wèn)題可能在這兒:http://groups.google.com/group/modwsgi/browse_thread/thread/59612820615eceaf,Graham(WSGI的作者)在這個(gè)帖子里說(shuō):
That is, Python 2.6+ links to newer MS C runtime library that Apache doesn’t and C extension modules which are somehow dependent on the newer MS C runtime library will not load properly.
就是:Apache鏈接的C動(dòng)態(tài)庫(kù)與Python2.6+不同,因此后者的C擴(kuò)展庫(kù)(比如_imaging)不能工作在前者的環(huán)境里。解決的辦法是:
If I am sort of right, the solution may be to relink mod_wsgi.so for Windows with dependency on new MS C runtime library.
就是要重新編譯WSGI!問(wèn)題又回到了原點(diǎn)!
從這件事情上,我看到的是:Python在Windows上問(wèn)題重重,考慮到數(shù)不清、理還亂的C運(yùn)行時(shí)庫(kù)問(wèn)題以及復(fù)雜的編譯環(huán)境。相對(duì)而言,Linux的情況要好很多:借助于方便的安裝包功能,即使需要編譯安裝的Python庫(kù)也比較容易處理(BUG也比Windows要少)。
后記:
在Linux服務(wù)器上,我的Python+WSGI+Apache的環(huán)境還算順利,但是Windows上做相同的事情看來(lái)難很多。但是應(yīng)用的開(kāi)發(fā)、測(cè)試需要一個(gè)同實(shí)際相當(dāng)?shù)沫h(huán)境,如果在Windows上開(kāi)發(fā)、測(cè)試時(shí)用簡(jiǎn)易Web服務(wù)器,部署時(shí)采用Apache+WSGI,顯然是不大合適的。那么,最終的解決方式,看來(lái)就是在Linux上做開(kāi)發(fā)。不過(guò)要我舍棄經(jīng)營(yíng)多年的Windows,仍然不是一件輕易的事情。
原文鏈接:http://www.nearby5.com/2011/06/29/python-in-my-view/
【編輯推薦】