Product deploy using NAnt and NSIS
参考网址
运行环境配置
解压缩附件NAnt和NSIS到一个固定目录(不能带空格的目录),例如:D:\Programs
配置 MSBUILD
将C:\WINDOWS\Microsoft.NET\Framework\v3.5加入环境变量
验证方式:命令行运行msbuild, 看到版本信息则为成功。
配置NAnt
将D:\Programs\NAnt\bin加入环境变量
验证方式:命令行运行nant, 看到版本信息则为成功。
配置NSIS
将D:\Programs\NSIS加入环境变量
验证方式:命令行运行makensis, 看到版本信息则为成功。
NAnt
ant是一个类似于bat和make的批处理工具,在.Net应用中称为NAnt。和其他工具不同的是,NAnt使用XML配置文件的形式作为工具的语言,更容易上手。详细介绍可参见http://nant.sourceforge.net
NAnt配置文件
NAnt的默认配置文件称为default.build(也可通过参数指定读取一个自定义的build文件),使用命令行进入 default.build所在的目录,直接执行nant,即可自动运行配置文件中的默认任务(target)。
<?xml version="1.0" encoding="utf-8" ?> <project name="MySolution" default="deploy"> <property name="build.dir" value="build" /> <property name="deploy.dir" value="deploy" /> <property name="nsis.script" value="deploy.nsi" /> <property name="sln.dir" value="." /> <property name="sln.name" value="MySolution.sln" /> <property name="bin.dir" value="${sln.dir}\MySolution\bin\Release" /> <target name="compile" description="compiles everything to release"> <exec program="msbuild" commandline="${sln.dir}\${sln.name} /t:Rebuild /p:Configuration=Release" /> </target> <target name="clean"> <delete dir="${build.dir}" if="${directory::exists(build.dir)}"/> <delete dir="${deploy.dir}" if="${directory::exists(deploy.dir)}"/> </target> <target name="init" depends="clean" description="initial compilation setup"> <mkdir dir="${build.dir}" /> <mkdir dir="${deploy.dir}" /> </target> <target name="rebuild" depends="compile, init"> <copy todir="${build.dir}\MySolution"> <fileset basedir="${bin.dir}"> <exclude name="*.vshost.exe"/> <exclude name="*.vshost.exe.config"/> <include name="*.exe"/> <include name="*.dll"/> <include name="*.config"/> </fileset> </copy> </target> <target name="deploy" depends="rebuild"> <exec program="makensis" commandline=' /X"SetCompressor /FINAL lzma" ${nsis.script}' /> </target> </project>
NAnt语法解释
设置项目名称,配置默认target。
<project name="MySolution" default="deploy">
定义属性名称,可以在下文中引用,例如"${sln.dir}\${sln.name}",效果等价于".\MySolution.sln"。
<property name="build.dir" value="build" /> <property name="deploy.dir" value="deploy" /> <property name="nsis.script" value="deploy.nsi" /> <property name="sln.dir" value="." /> <property name="sln.name" value="MySolution.sln" /> <property name="bin.dir" value="${sln.dir}\MySolution\bin\Release" />
定义一个名为compile的target,内容为执行msbuild,参数为".\MySolution.sln /t:Rebuild /p:Configuration=Release",这个任务表示Release编译MySolution.sln。之后在命令行中执行"nant compile",则会完成项目Release编译任务。
<target name="compile" description="compiles everything to release"> <exec program="msbuild" commandline="${sln.dir}\${sln.name} /t:Rebuild /p:Configuration=Release" /> </target>
定义一个名为clean的target,内容为删除build和deploy这两个文件夹,如果文件夹存在的话。
<target name="clean"> <delete dir="${build.dir}" if="${directory::exists(build.dir)}"/> <delete dir="${deploy.dir}" if="${directory::exists(deploy.dir)}"/> </target>
定义一个名为init的target,这个任务依赖于clean任务,意思就是在执行init之前,会自动先执行clean任务。init任务内容是创建build和deploy文件夹。
<target name="init" depends="clean" description="initial compilation setup"> <mkdir dir="${build.dir}" /> <mkdir dir="${deploy.dir}" /> </target>
定义一个名为rebuild的target,这个任务依赖于先依赖于compile再依赖于init,那么在执行rebuile任务时,其实是按照 compile->init->rebuild的顺序执行。rebuild任务内容是将compile任务编译好的文件复制到 build\MySolution文件夹下,复制过程中只复制exe,dll,config,并且排除了 vshost.exe,vshost.exe.config文件。
<target name="rebuild" depends="compile, init"> <copy todir="${build.dir}\MySolution"> <fileset basedir="${bin.dir}"> <exclude name="*.vshost.exe"/> <exclude name="*.vshost.exe.config"/> <include name="*.exe"/> <include name="*.dll"/> <include name="*.config"/> </fileset> </copy> </target>
定义一个名为deploy的target,任务依赖于rebuild,它的最终执行顺序便是 compile->init->rebuild->deploy。任务内容是使用makensis命令进行程序打包。 commandline中的内容是makensis的运行参数,设置了打包的脚本文件名,打包的压缩算法,压缩级别,makensis的具体运行参数说明可参见http://nsis.sourceforge.net
<target name="deploy" depends="rebuild"> <exec program="makensis" commandline=' /X"SetCompressor /FINAL lzma" ${nsis.script}' /> </target>
NSIS
NSIS(Nullsoft Scriptable Install System),它是一个脚本化的安装程序打包工具,它的优势在于支持脚本化配置安装程序打包,这样就有利于和其他部署工具配合使用。详细介绍可参见http://nsis.sourceforge.net
NSIS脚本
在上文中的NAnt中有说到makensis命令读取脚本文件进行打包。下面就是一个比较典型的程序打包脚本。
!include WordFunc.nsh
!insertmacro VersionCompare
!include LogicLib.nsh
!ifndef COMPRESS_DIR
!define COMPRESS_DIR ".\build"
!define TOOL_DIR ".\tool"
!endif
!define PRODUCT_NAME_CN "测试程序"
!define PRODUCT_NAME_EN "MySolution"
!define PRODUCT_VERSION "V1.0"
!define PRODUCT_PUBLISHER_CN "上海金桥信息工程有限公司"
!define PRODUCT_PUBLISHER_EN "SHGBIT"
!define INSTALL_NAME "测试程序-${PRODUCT_VERSION}"
; The default installation directory
InstallDir $PROGRAMFILES\${PRODUCT_PUBLISHER_EN}\${PRODUCT_NAME_EN}
Name "${PRODUCT_NAME_EN}"
# name the installer
outFile ".\deploy\${INSTALL_NAME}.exe"
!include "MUI.nsh"
!define MUI_ICON ".\install-res\ico-inst.ico"
!define MUI_UNICON ".\install-res\ico-uninst.ico"
!define MUI_WELCOMEFINISHPAGE_BITMAP ".\install-res\side.bmp"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP ".\install-res\header.bmp"
;!define MUI_FINISHPAGE_RUN "$INSTDIR\xxx.exe"
;Install Pages (1-6)
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE ".\install-res\LICENSE"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
;Uninstall Pages (1-2)
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
;Languages
!insertmacro MUI_LANGUAGE "SimpChinese" # first language is the default language
# !insertmacro MUI_LANGUAGE "English"
BrandingText "${INSTALL_NAME}"
DirText "安装程序将安装 $(^NameDA) 在下列文件夹。要安装到不同文件夹,单击 [浏览(B)] 并选择其他的文件夹。 $_CLICK"
Section "All Components " AllSection
SetOutPath "$INSTDIR"
File /r "${COMPRESS_DIR}\MySolution\*.*"
SectionEnd
Section -PostInstallSection
WriteUninstaller "$INSTDIR\Uninstall.exe"
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME_EN}"
CreateShortCut "$DESKTOP\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME_EN}\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME_EN}\卸载.lnk" "$INSTDIR\Uninstall.exe"
CreateShortCut "$SMSTARTUP\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "DisplayName" "${PRODUCT_NAME_EN}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "UninstallString" "$INSTDIR\uninstall.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "DisplayIcon" "$INSTDIR\ico-inst.ico"
SectionEnd
Section Uninstall
RMDir /r /REBOOTOK "$INSTDIR"
RMDir /r /REBOOTOK "$SMPROGRAMS\${PRODUCT_NAME_EN}"
Delete /REBOOTOK "$DESKTOP\${INSTALL_NAME}.lnk"
Delete /REBOOTOK "$SMSTARTUP\${INSTALL_NAME}.lnk"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}"
SectionEnd
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
Function .onInstSuccess
; MessageBox MB_YESNO|MB_ICONQUESTION "安装完成,系统重启后才能生效,是否立即重启?" IDNO +2
; Reboot
FunctionEnd
Function un.onInit
!insertmacro MUI_UNGETLANGUAGE
FunctionEnd
Function un.onUninstSuccess
; MessageBox MB_YESNO|MB_ICONQUESTION "安装完成,系统重启后才能生效,是否立即重启?" IDNO +2
; Reboot
FunctionEnd
NSIS脚本语法解释
符号说明
!XXXX NSIS脚本的关键字
;和# NSIS脚本注释标记
定义COMPRESS_DIR和TOOL_DIR两个变量,用来保存目录位置
!ifndef COMPRESS_DIR !define COMPRESS_DIR ".\build" !define TOOL_DIR ".\tool" !endif
定义几个变量,用来保存程序名称,版本号,公司名称
!define PRODUCT_NAME_CN "测试程序" !define PRODUCT_NAME_EN "MySolution" !define PRODUCT_VERSION "V1.0" !define PRODUCT_PUBLISHER_CN "上海金桥信息工程有限公司" !define PRODUCT_PUBLISHER_EN "SHGBIT"
定义变量保存打包生成的安装程序的文件名
!define INSTALL_NAME "测试程序-${PRODUCT_VERSION}"
设置程序安装的默认目录,$PROGRAMFILES=X:\Program Files,是NSIS自带的变量
InstallDir $PROGRAMFILES\${PRODUCT_PUBLISHER_EN}\${PRODUCT_NAME_EN}
设置程序名称,这个名称将在安装包的标题栏上显示
Name "${PRODUCT_NAME_EN}"
设置生成安装包的具体路径
outFile ".\deploy\${INSTALL_NAME}.exe"
设置安装过程中显示的图片文件
!define MUI_ICON ".\install-res\ico-inst.ico" !define MUI_UNICON ".\install-res\ico-uninst.ico" !define MUI_WELCOMEFINISHPAGE_BITMAP ".\install-res\side.bmp" !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP ".\install-res\header.bmp"
设置是否安装完成后运行程序
;!define MUI_FINISHPAGE_RUN "$INSTDIR\xxx.exe"
设置安装过程的步骤,下面定义了5个步骤,分别为欢迎、许可协议、设置安装目录、安装进度、完成安装。
!insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE ".\install-res\LICENSE" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH
设置卸载过程的步骤,下面定义了5个步骤,分别为卸载确认、卸载完成。
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
设置安装过程的语言选择界面,下面只定义了一种语言(简体中文)。
!insertmacro MUI_LANGUAGE "SimpChinese" # first language is the default language# !insertmacro MUI_LANGUAGE "English"
设置安装过程中界面下方虚线上写的名称
BrandingText "${INSTALL_NAME}"
设置安装过程中,选择安装目录阶段时显示的提示文字信息
DirText "安装程序将安装 $(^NameDA) 在下列文件夹。要安装到不同文件夹,单击 [浏览(B)] 并选择其他的文件夹。 $_CLICK"
Section有些相当于C#中Event的意思,下面这段表示在所有Section中设置输出路径为"$INSTDIR",设置需要打包的文件为"${COMPRESS_DIR}\MySolution\*.*",/r表示自动覆盖已存在文件。SetOutPath和File都是NSIS的内置函数,还有之前出现过的BrandingText、DirText之类的都是内置函数。
Section "All Components " AllSection SetOutPath "$INSTDIR" File /r "${COMPRESS_DIR}\MySolution\*.*" SectionEnd
这是安装过程中文件复制阶段完成后的事件(注:并非点击完成按钮后整个安装过程结束时的事件),下面这段在事件里生成了uninstall.exe 程序,开始菜单添加了快捷方式,桌面添加了快捷方式,系统开机启动里添加了快捷方式,系统注册表中添加了软件安装信息(用于在控制面板的添加删除程序里找到MySolution这个软件)
Section -PostInstallSection WriteUninstaller "$INSTDIR\Uninstall.exe" CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME_EN}" CreateShortCut "$DESKTOP\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe" CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME_EN}\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe" CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME_EN}\卸载.lnk" "$INSTDIR\Uninstall.exe" CreateShortCut "$SMSTARTUP\${INSTALL_NAME}.lnk" "$INSTDIR\MySolution.exe" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "DisplayName" "${PRODUCT_NAME_EN}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" "DisplayIcon" "$INSTDIR\ico-inst.ico" SectionEnd
这是程序卸载过程中文件删除阶段完成后的事件,下面这段根据之前的PostInstallSection中写的内容依次进行了删除,这里需要注意卸载过程的完整,否则就成了卸载不干净的垃圾软件了^.^。/r表示递归删除文件夹,/REBOOTOK表示如果文件被占用,则重启之后自动删除。
Section Uninstall RMDir /r /REBOOTOK "$INSTDIR" RMDir /r /REBOOTOK "$SMPROGRAMS\${PRODUCT_NAME_EN}" Delete /REBOOTOK "$DESKTOP\${INSTALL_NAME}.lnk" Delete /REBOOTOK "$SMSTARTUP\${INSTALL_NAME}.lnk" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_EN}" SectionEnd
这是双击安装程序时的事件,这里设置为双击之后出现语言选择界面
Function .onInit
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
这是安装程序退出时的事件,这里将多语言资源卸载
Function un.onInit
!insertmacro MUI_UNGETLANGUAGE
FunctionEnd
这是安装成功的事件,可以在这个阶段弹出是否要重启的确定框。
Function .onInstSuccess ; MessageBox MB_YESNO|MB_ICONQUESTION "安装完成,系统重启后才能生效,是否立即重启?" IDNO +2 ; Reboot FunctionEnd
这是卸载成功的事件,可以在这个阶段弹出是否要重启的确定框。
Function un.onUninstSuccess ; MessageBox MB_YESNO|MB_ICONQUESTION "安装完成,系统重启后才能生效,是否立即重启?" IDNO +2 ; Reboot FunctionEnd