Qt - 跨平台程序打包发布
文章目錄
- Qt跨平臺(tái)
- Java跨平臺(tái)實(shí)現(xiàn)
- Qt跨平臺(tái)實(shí)現(xiàn)
- Qt - Windows打包發(fā)布
- 最小依賴庫(kù)
- Windeployqt
- Enigma Virtual Box 打包為可獨(dú)立運(yùn)行exe
- Inno Setup 封裝為安裝包
- 如何修改版本信息
- 修改.pro
- rc資源文件
- Qt - Linux打包發(fā)布
- 拷貝依賴庫(kù)
- linuxdelpoyqt
- 參考鳴謝
Qt跨平臺(tái)
Qt 的跨平臺(tái)為 一次編碼,處處編譯,這與 Java 依賴虛擬機(jī)實(shí)現(xiàn)的 一次編譯,處處運(yùn)行 是不同的。
Java跨平臺(tái)實(shí)現(xiàn)
Java 是把針對(duì)不同平臺(tái)與操作系統(tǒng)的跨系統(tǒng)核心代碼抽象出來(lái),形成單獨(dú)的 JVM層(java virtual machine),Java 代碼運(yùn)行在 JVM 上,把跨平臺(tái) java語(yǔ)言框架問(wèn)題 分解為在不同平臺(tái)上設(shè)計(jì) JVM的問(wèn)題,結(jié)構(gòu)簡(jiǎn)單、邏輯清晰、易于實(shí)現(xiàn) 1。
為此,Java 付出了犧牲效率的代價(jià)。Java 語(yǔ)言需要先通過(guò) JVM 再映射到操作系統(tǒng)里,最后由CPU 執(zhí)行,執(zhí)行過(guò)程多了一步。早期由于 Java語(yǔ)言 主要使用 解釋性編譯器,從而導(dǎo)致運(yùn)行效率進(jìn)一步降低。但是隨著 即時(shí)編譯技術(shù)(JIT) 的推出,尤其是硬件計(jì)算速度的大幅提升,Java運(yùn)行效率 問(wèn)題基本得到解決 1。
Qt跨平臺(tái)實(shí)現(xiàn)
Qt平臺(tái) 封裝了針對(duì)不同平臺(tái)的類庫(kù),API 。這些都被上層做了封裝,對(duì)我們開發(fā)者來(lái)說(shuō)操作各種平臺(tái)的接口都是一樣的 1。以我最近使用的 QSerialPort 為例子,在 Qserialport.h 中可發(fā)現(xiàn)以下蛛絲馬跡:
Qserialport.h(源碼可戳)
//line 74 #if defined(Q_OS_WIN32)typedef void* Handle; #elsetypedef int Handle; #endif//line 307 #if defined(Q_OS_WIN32)Q_PRIVATE_SLOT(d_func(), bool _q_startAsyncWrite()) #endifQSerialPort.cpp(源碼可戳)
//line 90 #if defined(Q_OS_WIN32): readChunkBuffer(QSERIALPORT_BUFFERSIZE, 0) #endif {writeBufferChunkSize = QSERIALPORT_BUFFERSIZE;readBufferChunkSize = QSERIALPORT_BUFFERSIZE; } //line 1253 qint64 QSerialPort::bytesToWrite() const {qint64 pendingBytes = QIODevice::bytesToWrite(); #if defined(Q_OS_WIN32)pendingBytes += d_func()->writeChunkBuffer.size(); #endifreturn pendingBytes; }可見 QSerialPort 提供的接口是使用 宏 做了跨平臺(tái)處理的。
那么 Qt 為我們提供的跨平臺(tái)接口有那些呢?
Qt的界面,Qt封裝的一些庫(kù)包,數(shù)據(jù)結(jié)構(gòu)以及算法…
對(duì)于 Qt項(xiàng)目 中不提供跨平臺(tái)的部分,則需要我們自己實(shí)現(xiàn),常用的就是 宏。
例如換行操作:
#ifdef Q_OS_WIN32qDebug() << "Windows換行!\r\n"; #else//假設(shè)是LinuxqDebug()<<"unWindows換行!\n "; #endif好了下面進(jìn)入正題,Qt - Windows程序及Linux程序打包發(fā)布。
Qt - Windows打包發(fā)布
最小依賴庫(kù)
在 QtCore 中,當(dāng)我們把構(gòu)建方式選為Release,將生成 *.exe 文件
直接打開該文件會(huì)提示 缺少xxx.dll 等錯(cuò)誤。
我們可在 Qt 的編譯器路徑下搜索缺失的 dll文件;
我的路徑是 xxx\QT5.9.3\5.9.3\mingw53_32\bin,找到后將其放到可執(zhí)行文件· 同一路徑 下。
下圖是我復(fù)制的 dll庫(kù),應(yīng)該是 最小依賴庫(kù) 了。
Windeployqt
作為懶鬼,我堅(jiān)信懶是人類發(fā)展的原動(dòng)力。
于是我發(fā)現(xiàn)了一個(gè)便捷的工具 Windeployqt,它將幫助我們將依賴庫(kù)復(fù)制到指定目錄中。
例如我這在 D盤 創(chuàng)建了一個(gè) UHelper文件夾 ,然后將前面生成的 UHelper.exe 移動(dòng)進(jìn)去。
打開Qt for Desktop;
執(zhí)行 windeployqt *.exe。
可以發(fā)現(xiàn),依賴的庫(kù)都復(fù)制進(jìn)去了
Enigma Virtual Box 打包為可獨(dú)立運(yùn)行exe
我們可以將上面的 exe文件 及 dll文件 打包給別人,但是這樣一點(diǎn)也不酷。
有沒(méi)有辦法直接將 exe 和 所需的dll庫(kù) 都打包為一個(gè)exe文件呢?
還真有,Enigma Virtual Box 就是一個(gè)不錯(cuò)的選擇。
下載地址見:Enigma Virtual Box官網(wǎng)
ps:如果是使用 Windeployqt 添加的庫(kù),把所有添加的 dll及文件夾都拖選添加至 Enigma Virtual Box 即可。
切記:文件夾也要,并且不要試圖去改變它。
執(zhí)行完成后,就生成了一個(gè)獨(dú)立可執(zhí)行程序。
Inno Setup 封裝為安裝包
下載地址見:Inno Setup官網(wǎng)
使用流程可參考 2 Inno setup 打包教程
生成安裝程序如下:
安裝完成后的文件目錄如下:
有別于直接移植的是,在控制面板中是可以查找得到該程序的(即修改了注冊(cè)表)。并且它給我們提供了一個(gè)卸載程序。
如何修改版本信息
到此為止我們生成的可執(zhí)行文件都是沒(méi)有詳細(xì)信息的。
修改.pro
最簡(jiǎn)單的方法莫過(guò)于直接在 pro文件 中添加以下代碼。
下面列舉了一些常用信息 3 4:
//版本信息 VERSION = xx.xx.xx.xx //圖標(biāo) RC_ICONS = xxxx.ico //公司名稱 QMAKE_TARGET_COMPANY = "" //產(chǎn)品名稱 QMAKE_TARGET_PRODUCT = "" //文件說(shuō)明 QMAKE_TARGET_DESCRIPTION = "" //版權(quán)信息 QMAKE_TARGET_COPYRIGHT = "" //中文(簡(jiǎn)體) RC_LANG = 0x0004rc資源文件
由于 rc文件 是 Windows平臺(tái)相關(guān)的東西,Qt助手 中對(duì)于 rc文件 幾乎沒(méi)有任何介紹 5。
使用可查看本文參考 - 傳送門 。
Qt - Linux打包發(fā)布
將項(xiàng)目拷貝到 Ubuntu18.04;
Qt環(huán)境 與 Windows下的相同,均為 Qt5.9.3;
移過(guò)去后,UI 顯示有點(diǎn)問(wèn)題,于是修改了一下 UI;
然后用 Release編譯,即生成可執(zhí)行文件 UHelper。
由于 Ubuntu自帶了Qt庫(kù) 6,我們可以直接運(yùn)行:
程序運(yùn)行效果:
若非 Ubuntu 系統(tǒng)則需要拷貝so庫(kù)。
拷貝依賴庫(kù)
可以使用 ldd命令 查看其依賴庫(kù)及路徑:
ldd UHelper //or ldd ./UHelper
一個(gè)個(gè)復(fù)制很麻煩,為此可以借助 shell腳本 完成 so庫(kù) 的復(fù)制:
執(zhí)行:
chmod 777 pack.sh ./pack.sh復(fù)制完以后的結(jié)果如下圖所示:
再編寫一個(gè)可執(zhí)行文件;
UHelper.sh
#!/bin/sh appname=`basename $0 | sed s,\.sh$,,` dirname=`dirname $0` tmp="${dirname#?}" if [ "${dirname%$tmp}" != "/" ]; then dirname=$PWD/$dirname fi LD_LIBRARY_PATH=$dirname export LD_LIBRARY_PATH $dirname/$appname "$@"注意:這里的腳本名必須和可執(zhí)行文件名一致。
通過(guò)運(yùn)行此腳本而不是可執(zhí)行文件,可以確保動(dòng)態(tài)鏈接程序?qū)⒄业絈t庫(kù) 7。
linuxdelpoyqt
linuxdeployqt 可以理解為 Windeployqt 的 Linux 版本,讓你的打包如絲般順滑。
同時(shí),linuxdelpoyqt 是一個(gè)開源項(xiàng)目,下載地址見 Github-linuxdelpoyqt
下載完成后我們給它重命名為 delpoyqt。
執(zhí)行一下:
但是,我們?cè)谄渌窂较抡{(diào)用則顯得很不方便。
為此可將其移動(dòng)到 /usr/local/bin,這樣在任何地方都可以使用 deployqt。
sudo mv ./deployqt /usr/local/bin驗(yàn)證:
打包:
AppImage 的文檔提到,其理念是:應(yīng)用程序應(yīng)建立在最舊的系統(tǒng)上,以使它們可以在較新的系統(tǒng)上運(yùn)行 8。
至于原因,其解釋為:這樣就可以排除某些 基礎(chǔ)庫(kù),而這些 基礎(chǔ)庫(kù) 可以在所有主要的 桌面Linux發(fā)行版 中找到,從而減少了 One app = one file 的開銷 8。
顯然 Linuxdeployqt 的作者是非常認(rèn)同這種做法的。
probonopd :我認(rèn)為應(yīng)用程序開發(fā)人員只是為最新和最大的發(fā)行版進(jìn)行開發(fā)而“懶惰”,并告訴用戶“僅升級(jí)您的OS即可使用此應(yīng)用程序” 9。
目前所支持的最新Ubuntu LTS版本為16.04。
安裝Ubuntu16.04鏡像,記得選 arm版 并安裝 Qt、Linuxdeployqt…
重復(fù)之前的步驟,再重新執(zhí)行:
sudo deployqt Uhelper -appimage
這里提示圖標(biāo)的問(wèn)題,可以暫時(shí)忽略。
如何設(shè)置圖標(biāo),如何讓軟件開機(jī)自啟,如何打包為 deb文件,可參考 在Linux下使用linuxdeployqt發(fā)布Qt程序 10。
參考鳴謝
《Qt平臺(tái)體系與應(yīng)用——Qt5.5+核心方法、技巧與案例》 ?? ?? ??
Inno setup 打包教程 ??
How to Get Current App Version in Qt ??
Qt 之生成 Window 資源文件(.rc 文件) ??
Qt 之添加 Windows 資源文件(.rc文件) ??
01-為什么要用Qt開發(fā)(Qt跨平臺(tái)應(yīng)用開發(fā)) ??
Qt for Linux/X11 - Deployment ??
AppImage-Docs-Introduction-Concepts ?? ??
Latest continuous linuxdeployqt build does not work on Ubuntu 16.04 LTS and openSUSE Leap 15.0 #340 ??
在Linux下使用linuxdeployqt發(fā)布Qt程序 ??
總結(jié)
以上是生活随笔為你收集整理的Qt - 跨平台程序打包发布的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: pl中xmp文件的修改与保存
- 下一篇: VSCode+Marp:用Markdow