Qt之打包发布程序 (NSIS)

写好了程序之后要关心的就是怎么将程序打包成一个安装包发给用户了,这里就推荐一个功能比较全面的打包脚本NSIS。在一般情况下,只要不是特别傻逼的需求 (纠结安装包字符串显示的大爷惹不起惹不起....) 都是能实现的。

Qt程序处理

编译程序的release版

1.IDE版
构建方式换成Release,点击Qt Creator的运行按钮

2.命令行版(方便自动化构建)

set PATH=c:\Qt\Qt5.7.0\5.7\mingw53_32\bin;%PATH%
set PATH=c:\Qt\Qt5.7.0\Tools\mingw530_32\bin;%PATH%
cd %~dp0
mingw32-make.exe clean
qmake.exe Demo.pro -spec win32-g++ "CONFIG+=release" && mingw32-make.exe qmake_all
mingw32-make.exe -j4

查找Qt程序需要的动态库文件

直接将Qt的release目录拷贝到一个没装Qt的电脑里,会发现无法运行,这是因为有的Qt核心的动态库并不会在构建的时候放到该目录下,需要额外添加,Qt给我们提供了一个方便的工具来查找程序需要的相关dll,windeployqt.exe。

  1. widget版:
set PATH=c:\Qt\Qt5.7.0\5.7\mingw53_32\bin;%PATH%
set PATH=c:\Qt\Qt5.7.0\Tools\mingw530_32\bin;%PATH%
windeployqt.exe Demo.exe --dir %PRODUCT_DIR%

2.含有qml界面版:

set PATH=c:\Qt\Qt5.7.0\5.7\mingw53_32\bin;%PATH%
set PATH=c:\Qt\Qt5.7.0\Tools\mingw530_32\bin;%PATH%
windeployqt.exe --qmldir   %QML_FILE_DIR% Demo.exe  --dir %PRODUCT_DIR%

3.莫名其妙缺少dll版:
上面通过windeployqt.exe查找后还是缺失的话,直接去Qt放dll的目录,把所有dll拷贝到release目录下,把你的程序运行起来,然后删除所有dll,提示占用不能删除留下来的就是你需要的。

NSIS打包

NSIS有界面化的工具HM VNISEdit,不过一般都得改,就直接用文本编辑器手敲好了。可以先用工具生成一个默认的模板看看,下面主要讲下特殊需求怎么通过脚本实现。

1.安装/卸载程序互斥:同时只能开启一个安装/卸载程序:

;安装程序互斥
!define Mutex_Install     "Demo_Mutex_Install"
!define Mutex_UnInstall   "Demo_Mutex_UnInstall"


Function CreateMutex
;检查安装互斥
ReCheck:
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${Mutex_Install}") i .R1 ?e'
Pop $R0
System::Call 'kernel32::CloseHandle(i R1) i.s'
;检查卸载互斥
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${Mutex_UnInstall}") i .R3 ?e'
Pop $R2
System::Call 'kernel32::CloseHandle(i R3) i.s'
;判断安装/卸载互斥的存在
${If} $R0 != 0
MessageBox MB_RetryCancel|MB_ICONEXCLAMATION "$(MutexInstallMessage)" IdRetry ReCheck
Quit
${ElseIf} $R2 != 0
MessageBox MB_RetryCancel|MB_ICONEXCLAMATION "$(MutexUninstallMessage)" IdRetry ReCheck
Quit
${Else}
;创建安装互斥
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${Mutex_Install}") i .R1 ?e'
Pop $R0
StrCmp $R0 0 +2
Quit
${EndIf}
FunctionEnd

Function Un.CreateMutex
;检查安装互斥
ReCheck:
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${Mutex_Install}") i .R1 ?e'
Pop $R0
System::Call 'kernel32::CloseHandle(i R1) i.s'
;检查卸载互斥
CheckUnInstall:
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${Mutex_UnInstall}") i .R3 ?e'
Pop $R2
System::Call 'kernel32::CloseHandle(i R3) i.s'
;判断安装/卸载互斥的存在
${If} $R0 != 0
MessageBox MB_RetryCancel|MB_ICONEXCLAMATION "$(MutexInstallMessage)" IdRetry ReCheck
Quit
${ElseIf} $R2 != 0
MessageBox MB_RetryCancel|MB_ICONEXCLAMATION "$(MutexUninstallMessage)" IdRetry ReCheck
Quit
${Else}
;创建卸载互斥
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${Mutex_UnInstall}") i .R1 ?e'
Pop $R0
StrCmp $R0 0 +2
Quit
${EndIf}
FunctionEnd

Function .onInit
Call CreateMutex
...
FunctionEnd
  1. 检测所安装的程序是否有在运行,在的话弹个框提示杀进程:
...
 Push $R0
 CheckProc:
    Push "${PRODUCT_MAIN_APP_EXE}"
    ProcessWork::existsprocess
    Pop $R0
    IntCmp $R0 0 Done
    ; MessageBox MB_OKCANCEL|MB_ICONSTOP $(InstallWarningMessage) IDCANCEL Exit
    MessageBox MB_OKCANCEL|MB_ICONSTOP "$(InstallWarningMessage)" IDCANCEL Exit
    Push "${PRODUCT_MAIN_APP_EXE}"
    Processwork::KillProcess
    Sleep 1000
    Goto CheckProc
 Exit:
     Abort
 Done:
    Pop $R0
...
  1. 检测是否安装过旧版本,有的话提示卸载:
...
var /GLOBAL UNINSTALL_PROG
var /GLOBAL OLD_VER
var /GLOBAL OLD_PATH
    
ClearErrors
  ReadRegStr $UNINSTALL_PROG ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "UninstallString"
  IfErrors  FinishInit
  
  ReadRegStr $OLD_VER ${PRODUCT_UNINST_ROOT_KEY} ${PRODUCT_UNINST_KEY} "DisplayVersion"
  MessageBox MB_YESNOCANCEL|MB_ICONQUESTION "$(Uninstall_Old_Message)" /SD IDYES IDYES UninstallOld IDNO FinishInit
  Abort
  
UninstallOld:
  StrCpy $OLD_PATH $UNINSTALL_PROG -10

  ExecWait '"$UNINSTALL_PROG" /S _?=$OLD_PATH' $0
  DetailPrint "uninst.exe returned $0"
  Delete "$UNINSTALL_PROG"
  RMDir $OLD_PATH

FinishInit:
...
  1. 安装包多语言:
; 语言选择窗口常量设置
!define MUI_LANGDLL_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
!define MUI_LANGDLL_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
!define MUI_LANGDLL_REGISTRY_VALUENAME "NSIS:Language"

!define MUI_LANGDLL_WINDOWTITLE "$(LangDialog_Title)"
!define MUI_LANGDLL_INFO "$(LangDialog_Text)"
!define MUI_LANGDLL_ALLLANGUAGES
...
; 安装界面包含的语言设置
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
!insertmacro MUI_LANGUAGE "SimpChinese"
...

; 安装预释放文件
!insertmacro MUI_RESERVEFILE_LANGDLL
;!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
...
Function .onInit
 !insertmacro MUI_LANGDLL_DISPLAY 
...
FunctionEnd
  1. 界面美化
    如果制作的安装包不需要多语言的设置的话,可以通过一些别人写好的插件进行界面美化,如:nsNiuniuSkin
    下载下来就带了2个demo,改改就能自己用了,比较方便。Demo图示:
    Demo1.png
Demo2.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容