(本文是水木社區(qū)KDE與Qt編程技術版版主的文章,我覺得寫的很好克懊,就轉載過來了,原文地址:http://hgoldfish.com/blogs/article/103/)
經称咧看到網上有些論調說 Qt 程序無比龐大谭溉,甚至拿 .NET 程序來比,說 Qt 程序打包以后跟 .NET 安裝包差不多大橡卤。由此影響了很多人對 Qt 的選擇扮念。我覺得有必要對此做一些澄清——
顯然這個說法是錯誤的!碧库!
很容易理解柜与,雖然 Qt 提供了很多組件,但并非所有的組件都會被程序使用嵌灰,也并非所有的組件都需要打包到程序安裝包里面弄匕。以 Qt 5.7 為例,一個可以正常使用的 helloworld.exe 程序未壓縮不過 20M沽瞭,使用 lzma 壓縮算法迁匠,壓縮率 25%,壓縮完才 6M驹溃!
那盛傳的 Qt 上百 M 的容量又是怎么回事呢城丧?
這事從頭說起。
Qt4.4 引入了 Webkit 方便程序員往自己的程序里面嵌入 HTML 頁面豌鹤。剛開始倒也沒事亡哄,反正不主動包含到項目里面的話,程序安裝包并不會變大傍药。那會兒磺平,Qt 程序只要 8M(壓縮到3M)就搞定了。到了 Qt5 的時候 Webkit 換成了 Chromium 內核 Blink拐辽,名字改成了 QtWebEngine. Qt 開發(fā)者發(fā)現(xiàn) Blink 使用的 ICU拣挪,提供了比舊版本 Qt 更完整的國際化能力。于是俱诸,據說是因為一個誤會菠劝,Qt 開發(fā)者就在 Qt 5.0 里面強制依賴于 ICU 了。這個 ICU 包含了大量的國際化元信息睁搭,一下子增長了近 30M 的容量赶诊。笼平。
導致 Qt 容易增長還有另外一個重要原因,也就是 Qt 自從 4.7 以后引入的 QML舔痪。這是一個基于 ECMAScript 改造的語言寓调。從此以后,Qt 開發(fā)就有兩種流派锄码,一者使用原來的 C++ 語言進行開發(fā)夺英,另外一種使用 QML 語言進行開發(fā)。兩者共享一樣的底層設施滋捶,比如各種數據結構與事件循環(huán) QtCore 和 帶有 OpenGL 支持的 QtGui痛悯。但在上層,Qt 為 C++ 開發(fā)者們提供了 QtWidgets重窟,又為 QML 開發(fā)者提供了獨立的 QtQuick.
QtQuick 本身只有簡單的布局語言载萌,Qt 又在這個基礎上提供了 QtControls 模擬 Android,iOS 和 Windows 程序的外觀巡扇。早期的 Qt5 沒有設計好扭仁,導致使用 QML 時要引入一大堆程序可能用到的組件。所以一個 helloworld 下來霎迫,相當巨大斋枢。而且很奇怪的事,以 QtWidgets/C++ 的方式使用了 QtWebEngine 的話知给,也會引入幾乎所有的 QML 模塊瓤帚,那會兒一個簡單的程序會達到一百多兆的大小涩赢!
Windows 平臺還有一個特殊的問題「甏危現(xiàn)在 Qt 的圖形架構調用 OpenGL ES 2.0 進行底層的渲染,但剛安裝完的 Windows 只支持到 OpenGL 1.1筒扒,針對這個問題怯邪,早期的 Qt 在 configure 階段提供了兩種選項,一是使用與 Chromium 一樣的 ANGLE花墩,把 OpenGL 調用翻譯成 DirectX 調用悬秉,二者假定用戶的系統(tǒng)安裝了顯卡驅動,能夠支持 OpenGL 2.0冰蘑。前者需要包含幾個 ANGLE 的 DLL和泌,直接又增加了 17M 的容量!
所幸這些事情現(xiàn)在都解決了祠肥。
首先武氓,Qt 5 的早期版本已經提供了一個 configure 選項,可以不把 ICU 編譯到 Qt 里面,但是官方下載版本仍然默認包含 ICU县恕,后來 Qt 直接去掉了對 ICU 的依賴《現(xiàn)在的 Qt 在運行時找到 ICU 的 DLL 就會使用 ICU,否則調用系統(tǒng)的 API忠烛,如果都沒有属提,就湊合著用 Qt 內置的算法處理國際化。
其次美尸,QML 一些奇怪的依賴現(xiàn)在也去掉了垒拢。所以現(xiàn)在無論使用 QtWidgets 還是使用 QML,未壓縮時都只有 20M 左右的容量火惊。
最后一個,現(xiàn)在有多少用戶的電腦是沒有安裝顯卡驅動的呢奔垦?好吧屹耐,好像還真有,vmware 的虛擬機椿猎。但我覺得正常直接用系統(tǒng)自帶的 OpenGL 驅動足矣惶岭。Qt 現(xiàn)在會在運行的時候自動探測 ANGLE 是否存在,如果存在犯眠,就使用 ANGLE按灶,如果不存在,就使用系統(tǒng)自帶的 OpenGL筐咧,不必像以前那樣在 configure 階段就配置好鸯旁。另外,QtWidgets 沒有使用 OpenGL量蕊,所以使用 QtWidgets/C++ 的程序也可以把 ANGLE 的 DLL 都去掉铺罢。
說這么多,具體怎么操作呢残炮。非常簡單韭赘,用 Qt 5.7 來說,現(xiàn)在提供了一個名為 windeployqt.exe 的程序势就,位于 Qt 的 bin 目錄里面泉瞻。運行這個程序,后面帶程序名稱就行了:
- 創(chuàng)建一個 dist 目錄
- 把編譯好的 qttest.exe 復制到 dist 目錄苞冯。
- 打開 cmd.exe袖牙,cd 到 dist 目錄
4.1 運行 c:\qt5\bin\windeployqt.exe qttest.exe
4.2 對于 QML 程序,需要指定 QML 目錄: c:\qt5\bin\windeployqt.exe –qmldir d:\qttest qttest.exe
這時候就會看到 qt 已經把需要用到的 DLL 都復制過來了抱完。我會在這個基礎上再根據需要去掉一些東東:
- libEGL.dll, libGLESV2.dll 這兩個文件是 ANGLE 的文件贼陶,可以去掉。opengl32sw.dll 是軟件模擬 OpenGL,除非用戶的系統(tǒng)連 DirectX 支持都不完整——虛擬機環(huán)境就是這樣——不然這個文件也完全沒有用碉怔。 QtWidgets/C++ 程序都不用 OpenGL烘贴,所以直接去掉即可〈殡剩可在調用 windeployqt.exe 時加”–no-angle” 和 “–no-opengl-sw” 這兩個參數桨踪。
- 如果沒有使用 svg 的話,iconengines\qsvgicon.dll, imageformats\qsvg.dll, Qt5Svg.dll 這三個文件也可以刪掉
- 如果沒有國際化用戶的話芹啥,translations 里面的翻譯文件也可以刪掉锻离。
- QML 程序沒有使用 QtWidgets/C++ 可以刪掉 Qt5Widgets.dll
- 如果 imageformats 目錄里面有幾種圖像格式沒用上,也可以刪掉墓怀。我自己通常把整個目錄都刪掉汽纠,Qt已經編譯了 png 的支持,能讀寫程序包含的圖標就夠傀履,其它格式不重要虱朵。
- qmltooling 和 Qt5Network.dll 是用于 QML 調試用的,可以刪掉钓账。
經過以上裁剪碴犬,使用 7zip 壓縮完以后,一個 QtWidgets/C++ helloworld 程序最終只剩下 5.64M梆暮,一個 QtControls 程序是 5.86M, QtQuick 程序還會更小一些服协。
附注:
截止本文寫作時,Qt 5.8 已經發(fā)布了啦粹。在這個版本里面偿荷,不再依賴于 OpenGL ES 2.0,而是繞過 ANGLE唠椭,直接調用 DirectX 渲染遭顶,到 Qt 5.10 還要直接支持 Vulkan API。不過目前仍然是試驗性的泪蔫,有興趣的話可以看看 configure 的說明棒旗。
新的 Qt 5.8 重寫了 configure 系統(tǒng),能夠更深入地裁剪 Qt撩荣。最小未壓縮 5M 即可布署一個 QML 程序铣揉。
參考資料:
Qt 5 ICU
https://wiki.qt.io/Qt_5_ICU
http://wiki.qt.io/Qt-5-QLocaleDynamically Loading Graphics Drivers
http://doc.qt.io/qt-5/windows-requirements.html