天天看點

使用VC2005編譯真正的靜态Qt程式

首先,你應該該知道什麼叫靜态引用編譯、什麼叫動态引用編譯。我這裡隻是簡單的提提,具體的可以google一下。

動态引用編譯,是指相關的庫,以dll的形式引用庫。動态編譯的Exe程式尺寸比較小,因為相關的庫都沒有包含進來。當然,程式釋出的時候,還要把相關的庫也一并釋出出去。

靜态引用編譯,是指把相關的庫也一并引入Exe檔案。這是程式的尺寸就會很大,不過,程式釋出就會變得簡單很多。

其次,你可能會注意到我标題上寫了“真正”這兩個字。為什麼我要強調真正這兩個字呢?因為使用VC編譯的C或者C++程式,都需要相關的C runtime庫才能運作。如果你是VC6,相應的庫就叫MSVCR,如果是vc2005,那就是MSVCR08,vc2008就是MSVCR09。我這裡假設你安裝的是VC2005,請進入如下目錄:${VS Install Dir}\VC\redist\x86 和 ${System Driver}:\windows\WinSxS,你就會發現下面有很多很多的庫。沒錯,這裡相當一部分就是C runtime庫。

好了,言歸正傳,首先,我們用VC2005寫了一個不使用MFC的存C或者C++的程式,怎麼釋出給最終使用者呢?有兩個方法:

(1)靜态引用C runtime庫:打開“項目”->“XXX屬性”->“配置屬性”->“C/C++”->“代碼生成”->“運作時庫”。看到了吧?這裡一共有四個選項,其中MT開頭的是靜态引用,MD開頭的是動态引用,d結尾的是Debug調試版本,沒有d的是Release釋出版本,是以就一共有四個選項。我們選擇/MT,然後編譯程式(生成的程式應該不小),把這個程式發給使用者,然後使用者就可以直接運作了。

(2)動态引用C runtime庫:跟上面差不多,不過是用/MD選項編譯(程式應該隻是幾十K),然後發給使用者。這時,使用者是不能運作這個程式的,會報個什麼程式引導失敗,重裝系統可能會修複問題之類的提示。這是我們還要把C runtime庫一并發過去。把${VS Install Dir}\VC\redist\x86\Microsoft.VC80.CRT下的所有檔案(注意,是所有,包括那個.manifest檔案)發給使用者,使用者把這些檔案放在我們的程式的同一個目錄,然後再次運作,這時,程式就起來了(VC2005之後,C runtime庫的引用改變了很多,建議google一下)。

說完C runtime庫,就來說說Qt庫了,這裡我假設你用的是最新的Qt4.4.3。我們編譯Qt的時候,configure.exe有很多參數,大家可以configure.exe --help來看看,其中,預設生成的Qt庫(這裡預設的意思,是指沒有加-share或者-static參數)是動态引用的,也就是說,編譯完後,在QtDir的lib目錄下除了一大堆lib檔案外,還有一大堆的dll檔案。我們釋出我們的Exe程式的時候,需要把相應的Qt庫的Dll也一并發給使用者。

按照Qt的安裝手冊和網上一大堆大牛的說法,加上-static參數後,Qt就可以靜态編譯了,也就是說,lib目錄下之後一大堆lib檔案,沒有dll檔案。是否?我們做個試驗:

首先是設定變量:

set QTDIR=%CD%

set PATH=%PATH%;%QTDIR%\bin

set QMAKESPEC=win32-msvc2005

"C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"" x86

配置makefile:

configure -release -static -fast -qt-sql-odbc -qt-sql-sqlite -no-webkit

(這裡的參數就不一一說明了,建議讀者打入--help認真查查,特别注明一下,之是以-no-webkit,是因為新版的qt加上了Webkit,而這個東東編譯的時候非常耗時間,編譯後也很大,有100多M,并且我基本不會用到這個東東,是以忽略它)

然後

cd src  (我之是以直接進入src目錄nmake,是因為不想make其它不相幹的子產品,節省時間)

nmake

漫長的等待之後,我們發現lib下果然隻有一大堆lib檔案了,而且每個lib檔案的尺寸都在M以上,似乎已經成功了。然後我們在安裝了qt-vsintegration的VC2005建立一個Qt工程,然後編譯一個release版本。編譯的時候,問題來了。我們選擇/MD選項,這時連結就可以通過,但如果我們想要用/MT選項來使用靜态C runtime庫,就會報一大堆某某函數連結重複之類的錯誤。經驗告訴我們,之是以不能使用/MT來編譯,是因為另外一個庫——Qt庫使用了另外一種引用方式/MD(原則上來說,一個程式裡面的所有子產品,都應該使用同一種引用方式,具體可以google一下)。很顯然,我們編譯的所謂靜态Qt程式,一樣要背着微軟的C Runtime庫到處跑,還不夠“真正”的靜态。

怎麼才能做成完全的靜态呢?記得之前編譯wxWidgets的時候,它除了有SHARED=0或者1的選項之外,還有一個RUNTIME_LIBS = static or dynamic的選項,很顯然,這個RUNTIME_LIBS的選項就是我們想要的選項。不過我翻遍了Qt的安裝手冊以及網上大牛的文章,都沒有提及這個問題,我當時心裡就覺得奇怪,難道沒人遇到過這個問題?我又認真翻查了configure.exe的help,也沒有類似的選項,問題一下就僵住了。

回憶一下剛才我們編譯的時候,螢幕上調用cl.exe編譯的時候,有這樣一個參數:cl.exe .... -MD .... xxx.cpp,眼利的朋友一下就會發現,這個-MD就是c runtime動态引用的選項。然而,怎麼把這個-MD改成-MT呢?我們翻開剛才我們編譯的qt的src目錄下,随便找個目錄進去,打開Makefile.Release,我們就會看到CFLAGS=-MD ........,沒錯,就是這裡。我們隻要在這裡把-MD改成-MT,就會使用靜态c runtime庫編譯Qt了。我們當然不可能一個一個地替換這些makefile,關鍵是找出生成這些參數的模闆檔案。很顯然,它肯定在qt的mkspecs目錄,我們直奔win32-msvc2005目錄,果然找到一個qmake.conf檔案,果然找到一個QMAKE_CFLAGS_RELEASE = -O2 -MD,把這裡的-MD換成-MT,然後清理一下剛才的生成的配置資訊(網上又說用nmake confclean來清空,不過我沒有成功,貌似是使用了-fast參數的緣故,不過沒關系,把這個目錄删掉,重新解壓一份源代碼就可以了,然後把win32-msvc2005目錄下的qmake.conf的-MD換成-MT),重新

然後nmake

又是漫長的等待。不過我們不要幹等,看看出來的編譯指令,cl.exe .... -MT .... xxx.cpp,果然變成靜态c運作庫了。

編譯完之後,像剛才那樣,在VC2005建一個Qt的工程,然後用/MT這個選項編譯,OK,編譯成功,出來的Exe檔案大小是4.95M,貌似已經把C runtime庫嵌進來了。然後把這個程式放到使用者那裡運作,OK單個Exe檔案運作成功了。

至此,編譯真正靜态的Qt程式試驗完成。總結一下整個過程,首先是要有耐性,因為編譯一次Qt都至少兩個小時(當然,用一些技巧,例如-fast,-no-qmake,隻編譯src等等的技巧可以縮短很多時間),我來回就編譯了五次Qt;其次熟悉一些常見的編譯、連結的錯誤,例如一見到XXX庫已經引用之類的錯誤,馬上就聯想到應該是引用不同的庫導緻的;最後,要善于發現問題,查找問題。

http://www.cnblogs.com/bingcaihuang/archive/2010/12/01/1892765.html