一. 环境
操作系统:Windows 10
Qt版本:QT5.12.8
Visual Studio版本:Visual Studio 2017
NSIS版本:NSIS 3.08 增强版
Jenkins版本:2.346 (建议使用最新)
以下是环境搭建说明:
Windows下Jenkins软件安装说明及配置_枫蓝驿的博客
Visual Studio 2017下载及安装_枫蓝驿的博客
win10 安装 Qt 5.12.8 安装_枫蓝驿的博客
CentOS 安装Gitlab及 配置_枫蓝驿的博客
二、Jenkins 创建项目
2.1 新建项目
项目名称:自定义(必填项),最好和项目相关,区分不同项目
项目类型:Freestyle project 自由风格的项目
2.2 常规设置
Gitlab Connection 需要在插件中心安装Gitlab插件,并在System配置Gitlab Token方可使用
Rebuild 需要在插件中心 安装Rebuild插件方可使用
This project is parameterized支持参数化构建,定义一个唯一的参数名称.${PARAMETER_NAME},在脚本中通过
%PARAMETER_NAME%全局参数来获取参数的值
常用的有:
Choice Parameter 单选
git Parameter git参数
如下分别是单选和git参数示例:
配置完成后参数最终构建时的界面样式:
2.3 源码管理
源码管理支持git 及多repo的SCMs
默认git ,仅能添加一个主仓库,如存在多个依赖仓库时选择Multiple SCMs,Multiple SCMs需要在插件中心安装Multiple SCMs才能被支持。
一般在jenkins项目创建之前,需要把主repo,依赖repo进行汇总,然后便于在jenkins上进行添加,如下表有两个repo那这时候我们就选择Multiple SCMs添加多个git仓库了
git仓库 | 分支 |
主库: | ${Branch} |
${ToolBranch} |
2.4 构建触发器
触发远程构建器:配置一个构建项目的token,拼接在URL上,通过脚本调用URL来实现打包
如下:
http://192.168.3.24:8080/http://192.168.1.3:8080/view/AAA/job/DemoCI/build?token=
TOKEN_NAME
可以直接在浏览器直接打开这个地址旧可以触发构建
Build after other projects are built: 当前项目构建时依赖于其他项目,其他项目构建成功失败等条件时触发。
Build periodically:定时构建,支持cron语法
webhook :在gitlab项目中setting配置webhook并开启 GitLab triggers,根据配置条件,如push Merg,等事件触发构建,一般为Accepted Merge Request Events,
如果是使用jenkins做自动化代码静态检查,也会在push时触发;
GitHub hook trigger for GITScm polling:GItHUb一般国内用不到
Gitlab Merge Requests Builder:Merge Requests触发build,如果成功自动执行Merge
Poll SCM:jenkins定期去扫描repo改动,如有改动则触发构建,支持cron语法,不建议去用轮询来检测更改,因为每次会去检测整个工作区与gitlab服务器的差异,相当耗性能。
2.5 构建环境
构建环境常用的功能,开启控制台显示时间线,默认为不显示
2.6 构建步骤
由于我们是在windows下构建windows平台的应用程序,所以我们选择windows batch command来执行脚本,增加构建步骤——>Execute Windows batch command
2.7 Jenkin批处理调用示例
@echo off
call D:\Demo\DemoCI\01_CI.bat
2.8 Jenkins批处理调用顺序
01_CI.bat 分别按顺序来调用Build Deploy package Install等脚本
三、脚本详解
01_CI Jenkins目标脚本
rem表示注释,因为当前是调试环境,如果田间到jenkins执行时可以根据自身需求增减,jenkins全局参数可参考jenkins api进行调用,
定义全局变量
%CIDIR%:脚本目录,%~dp0 表示当前目录,使用%cd%也可以实现
%WORKSPACE%:Jenkins自身全局变量,为jenkins工作区目录
%Branch%:jenkins新建项目时,定义的git Paramer 参数名称
%BUILD_NUMBER%:jenkins当前编译的序号从0开始递增
PRODUCT_NAME:jenkins构建项目名称
@echo off
rem 定义全局变量
set CIDIR=%~dp0
set WORKSPACE=E:\workspace
REM set SRCDIR=%WORKSPACE%
REM set BRANCH_NAME=%Branch%
REM set BUILD_NUMBER=%BUILD_NUMBER%
set PRODUCT_NAME=analogclock
rem 回调编译、打包、安装包制作脚本
call %CIDIR%/02_build.bat
call %CIDIR%/03_deploy.bat
call %CIDIR%/04_Install.bat
02_build 批处理调用qmake编译
为什么要设置QTTDIR、QTMSDIR、VCDIR?
因为一台电脑上可能安装多个qt和visual studia版本,甚至有没有设置环境变量都不一定,如果使用默认那就有可能编译报错,甚至编译成功但是打开软件会提示0x000007f 这种无脑异常,找问题贼难找,那为了解决这个问题我们首先要做的是确认和开发中使用的环境一致(qt版本、vs版本)。
QTTDIR、QTMSDIR、VCDIR等vs和qt目录,均为默认安装时的目录,请确认和您的环境一致
第4行
第5行
第6行
vcvarsall.bat x86_amd64 ## 使用 32 位 x86 本机兼容工具生成 64 位 x64 代码。
第8行
第10行
第13行
第16行
第18行
-wnone 参数 ,不输出警告信息
-spec win32-msvc 参数,告诉 qmake 生成适用于 Windows 平台的 Microsoft Visual C++ 项目文件
"CONFIG += release" ,指定了构建类型为 release 版本
第19行
第23行
qt 编译脚本
@echo off
rem 设置VisualStudio和QT的目录
set WORKSPACE=E:\workspace
set QTTDIR=C:\Qt\Qt5.12.8\Tools\QtCreator\bin
set QTMSDIR=C:\Qt\Qt5.12.8\5.12.8\msvc2017_64\bin
set VCDIR="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat"
rem 设置构建目录
set BUILD_DIR=%WORKSPACE%\qt-build\AutoBuild\build
rem 设置需要编译的pro文件的地址
set TARGETPRO="%WORKSPACE%\qt-build\analogclock\analogclock.pro"
rem 编译前,清空编译缓存和旧文件
rmdir /s /q %BUILD_DIR% && mkdir %BUILD_DIR% && cd /d %BUILD_DIR%
rem 执行VS的脚本配置当前环境
call %VCDIR% x86_amd64
::配置构建参数
%QTMSDIR%/qmake.exe %TARGETPRO% -Wnone -spec win32-msvc "CONFIG += release"
%QTTDIR%/jom.exe /j 4 /f Makefile
%QTTDIR%/jom.exe -f Makefile.Release clean
REM ::构建完成之后清空对应的中间文件
cd .\release
if not exist "analogclock.exe" (
echo "**************************error: analogclock.exe no-exit******************************************"
exit 2
)
%QTMSDIR%\windeployqt.exe analogclock.exe
03_deploy copy静态文件
deploy 需要根据自身项目需求,来编写不同的脚本,大体的作用是将静态文件,依赖的dll文件,copy到预打包目录
chcp 65001
@ECHO off
SET BINDIR="%WORKSPACE%\qt-build\analogclock"
set RELEASE_DIR=%WORKSPACE%\qt-build\AutoBuild\build\release
mkdir %RELEASE_DIR%\config
xcopy /E /y /i %BINDIR%\*.cfg %RELEASE_DIR%\config
xcopy /E /y /i %BINDIR%\*.sql %RELEASE_DIR%\config
xcopy /E /y /i %BINDIR%\*.yml %RELEASE_DIR%\config
xcopy /E /y /i %BINDIR%\*.json %RELEASE_DIR%\config
xcopy /E /y /i %BINDIR%\*.dt %RELEASE_DIR%\config
xcopy /E /y /i %BINDIR%\*.qm %RELEASE_DIR%\config
echo {>>%RELEASE_DIR%\product.ini
echo "product_name":"analogclock",>>%RELEASE_DIR%\product.ini
echo "product_version":"V1.0.0",>>%RELEASE_DIR%\product.ini
echo "inner_product_version":"%BRANCH_NAME% ",>>%RELEASE_DIR%\product.ini
echo "file_version":"%VER%">>%RELEASE_DIR%\product.ini
echo }>>%RELEASE_DIR%\product.ini
04_package 打包安装包
NSISDIR:定义NSIS编译器目录
NSISSCRIPTDIR:定义NSIS脚本目录
chcp 65001
@echo off
set WORKSPACE=E:\workspace
set NSISDIR=E:\workspace\qt-build\NSIS
set NSISSCRIPTDIR=%WORKSPACE%\qt-build\AutoBuild
echo "*********************start makensis %data% %time%******************"
%NSISDIR%\makensis.exe %NSISSCRIPTDIR%\analogclock.nsi
echo "*********************end makensis %data% %time%******************"
05 NSIS脚本
第10行
第11行 !AddPluginDir "F:\Packge_Installer\NSIS\Plugins",NSIS路径需要改成您实际的NSIS路径
; include for some of the windows messages defines
!include "MUI2.nsh"
!include "WinMessages.nsh"
!include "LogicLib.nsh"
!include "x64.nsh"
!define "LIBRARY_X64"
!include "FileFunc.nsh"
; 定义打包路径
!define PackgePath "E:\workspace\qt-build"
!AddPluginDir "E:\workspace\qt-build\NSIS\Plugins"
; UAC进行权限请求 RequestExecutionLevel none|user|highest|admin
RequestExecutionLevel admin
SetCompressor lzma
SetCompressorDictSize 32
Unicode True
; OutPutProductName
!define analogclock_ViewerName "analogclock"
!define analogclock_exeName "analogclock"
!define DependentProduct "analogclock"
!define PRODUCTNAME "${analogclock_ViewerName}"
!define ORGNAME "QTBuild"
; ProductType
; Product Information
!define Version "V1.0.0"
!define FullVersion "1.0.0.6"
!define analogclock_UDI ""
!define analogclock_ProductName "QtGUI测试软件"
!define analogclock_ProductModel "analogclock"
!define analogclock_FileVersion "${FullVersion}"
!define analogclock_ProductVersion "${Version}"
!define analogclock_PublishDate "2022-01-30"
!define analogclock_LegalCopyright "Copyright@ 2022 xxxxxxxx Technology Co., LTD. All Rights Reserved."
!define analogclock_CompanyName "xxxxxx有限公司"
!define analogclock_Address "xxxxxxx大厦11层18室"
; Product File Version
VIProductVersion "${FullVersion}"
VIAddVersionKey /LANG=2052 "ProductName" "${analogclock_ProductName}"
VIAddVersionKey /LANG=2052 "FileDescription" "${analogclock_ProductModel}"
VIAddVersionKey /LANG=2052 "LegalCopyright" "Copyright(C) 2022 xxxxxxx Technology Co., LTD. All Rights Reserved."
VIAddVersionKey /LANG=2052 "ProductVersion" "${Version}"
VIAddVersionKey /LANG=2052 "FileVersion" "${FullVersion}"
; 安装和卸载程序图标
!define MUI_ICON "${PackgePath}\AutoBuild\static\logo.ico"
!define MUI_UNICON "${PackgePath}\AutoBuild\static\uninstx.ico"
!define MUI_PRODUCT "${PRODUCTNAME}"
; 定义输出安装包名称
!define /date PRODUCT_TIME %Y%m%d%H%M%S
OutFile "${PackgePath}\Install_${analogclock_ProductName}_${PRODUCT_TIME}.exe"
Name "${MUI_PRODUCT}"
; 展示安装细节
ShowInstDetails "show"
ShowUninstDetails "show"
AutoCloseWindow false
SetDateSave on
SetDatablockOptimize on
CRCCheck on
SilentInstall normal
; 定义安装路径
;InstallDir "$PROGRAMFILES64\${ORGNAME}"
InstallDir "D:\${ORGNAME}"
; 判断D盘存在与否确定安装路径
!define DrivePath "D:\"
;BrandingText "www.manual.com"
BrandingText " "
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!insertmacro MUI_PAGE_WELCOME
;!insertmacro MUI_PAGE_LICENSE textfile
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_WELCOME
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH
; Languages
!insertmacro MUI_LANGUAGE "SimpChinese"
!insertmacro MUI_LANGUAGE "English"
;---------------------------------------------------------------------------------------
;Installer Sections
Section "${analogclock_ViewerName}" S_2
SetOutPath "$INSTDIR\analogclock"
File /r "${PackgePath}\AutoBuild\build\release\*"
SetOutPath "$INSTDIR\analogclock"
WriteUninstaller "$INSTDIR\analogclock\uninst.exe"
SectionEnd
; 未选择组件禁止下一步(只针对Section生效)
Function .onSelChange
StrCpy $0 0
StrCpy $1 ${S_2}
${DoWhile} $1 <= ${S_2}
${If} ${SectionIsSelected} $1
StrCpy $0 1
${ExitDo}
${EndIf}
IntOp $1 $1 + 1
${Loop}
GetDlgItem $1 $HwndParent 1
EnableWindow $1 $0
FunctionEnd
;=============================================================================================================
;Uninstaller Sections
Section "Uninstall"
; make sure windows knows about the change
SendMessage ${HWND_BROADCAST} ${WM_SETTINGCHANGE} 0 "STR:Environment" /TIMEOUT=5000
nsExec::Exec "TASKKILL /F /IM ${analogclock_exeName}.exe /T"
RMDir /r "$INSTDIR\${analogclock_exeName}"
RMDir /r "$INSTDIR"
IfFileExists "$INSTDIR" 0 NoErrorMsg
MessageBox MB_OK "Note: $INSTDIR could not be removed!" IDOK 0 ; skipped if file doesn't exist
NoErrorMsg:
SectionEnd
编译输出安装包
NSIS 使用版本
QtBuild: Qt c++ jenkins使用批处理编译
四、编译完整demo开源仓库
此仓库已经开源,欢迎下载:
git clone https://gitee.com/fenglanyi/qt-build.git