本文用于记录如何安装与配置gitlab runner并搭建c++项目的自动编译及打包的过程。
一、gitlab runner安装
我要编译和打包的目标平台是windows平台,所以找了一台干净的windows主机,到gitlab官方网站下载了gitlab runner for windows的可执行文件,非常的简单,就一个可执行文件就够用了,放到一个剩余硬盘空间充足的盘符下面,创建个容易辨识的文件夹如gitlabrunner,把这个可执行文件放进去,然后准备安装为windows service和向gitlab 仓库进行注册,下面是它的命令行参数说明:
NAME:
gitlab-runner-windows-amd64.exe - a GitLab Runner
USAGE:
gitlab-runner-windows-amd64.exe [global options] command [command options] [arguments...]
VERSION:
18.0.2 (4d7093e1)
AUTHOR:
GitLab Inc. <support@gitlab.com>
COMMANDS:
list List all configured runners
run run multi runner service
register register a new runner
reset-token reset a runner's token
install install service
uninstall uninstall service
start start service
stop stop service
restart restart service
status get status of a service
run-single start single runner
unregister unregister specific runner
verify verify all registered runners
wrapper start multi runner service wrapped with gRPC manager server
fleeting manage fleeting plugins
artifacts-downloader download and extract build artifacts (internal)
artifacts-uploader create and upload build artifacts (internal)
cache-archiver create and upload cache artifacts (internal)
cache-extractor download and extract cache artifacts (internal)
cache-init changed permissions for cache paths (internal)
health-check check health for a specific address
proxy-exec execute internal commands (internal)
read-logs reads job logs from a file, used by kubernetes executor (internal)
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--cpuprofile value write cpu profile to file [%CPU_PROFILE%]
--debug debug mode [%RUNNER_DEBUG%]
--log-format value Choose log format (options: runner, text, json) [%LOG_FORMAT%]
--log-level value, -l value Log level (options: debug, info, warn, error, fatal, panic) [%LOG_LEVEL%]
--help, -h show help
--version, -v print the version
执行gitlab-runner-windows-amd64.exe install 就可以安装为windows服务了,然后再执行gitlab-runner-windows-amd64.exe register ,打开你的gitlab 仓库,找到仓库的“设置”-->“CI/CD”-->"RUNNER" ,点击展开,我这里的案例是这个gitlab runner只给我自己用,不打算给其他研发组使用,所以到“指定Runner”,复制“使用此网址注册Runner” 这里面的地址和注册令牌使用,然后为了和其他的gitlab runner进行区分,在输入tag标签的时候Enter tags
for
the runner (comma-separated):
输入qt,windows-builder,注意这里面的多个标签是用逗号分割的,Enter an executor的时候输入shell,这就完事了,然后把服务启动起来sc.exe start gitlabrunner ,可以打开windows的服务去查看服务有没有正常启动,其实就算是正常启动了,后续因为要改动环境变量等还是需要在正式使用之前再次重启这个服务的。
二、搭建编译环境
这里就简化记录,我是使用的vcpkg,正常安装visual studio 2022/vcpkg,这些并编译你要用到的c++库等。
三、编写gitlab ci/cd文件
写这玩意耗费了2天的时间,太麻烦了,在项目的根目录创建.gitlab-ci.yml文件,以下内容有删减:
stages:
- build
- package
variables:
# Windows平台的vcpkg路径环境变量
WINDOWS_VCPKG_ROOT: "C:\\vcpkg"
WINDOWS_VCPKG_DEFAULT_TRIPLET: "x64-windows"
# Windows Qt TOOLS BIN 路径配置 (for windeployqt and PATH)
WINDOWS_QT_TOOLS_BIN: "C:\\vcpkg\\installed\\x64-windows\\tools\\qt5\\bin"
# 构建配置
BUILD_TYPE: "Release"
# Windows平台构建任务
build_project_windows:
stage: build
tags:
- windows-builder
rules:
# 在master分支的所有提交上触发
- if: $CI_COMMIT_BRANCH == "master"
when: always
# 在其他分支的推送时也触发
- if: $CI_PIPELINE_SOURCE == "push"
when: always
# 手动触发
- when: manual
allow_failure: true
before_script:
- echo "Setting up Windows environment variables"
- $env:VCPKG_ROOT = $env:WINDOWS_VCPKG_ROOT
- $env:QT_BIN_DIR = $env:WINDOWS_QT_TOOLS_BIN
- $env:PATH += ";$env:VCPKG_ROOT;$env:QT_BIN_DIR"
- $env:CMAKE_TOOLCHAIN_FILE = "$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
- echo "Verifying environment"
- echo "Building on Windows platform"
- 'echo "VCPKG_ROOT: $env:VCPKG_ROOT"'
- 'echo "QT_BIN_DIR (for deploy): $env:QT_BIN_DIR"'
- echo "Creating build directory"
- if (!(Test-Path "build-windows")) { New-Item -ItemType Directory -Path "build-windows" }
script:
- 'echo "Step 3: Configuring CMake project"'
- echo "Configuring CMake project for Windows..."
- cd build-windows
- echo "CMake configuration parameters:"
- 'echo " VCPKG_ROOT: $env:VCPKG_ROOT"'
- 'echo " QT_BIN_DIR (for deploy): $env:QT_BIN_DIR"'
- >
cmake .. -G "Visual Studio 17 2022" -A x64
-DCMAKE_BUILD_TYPE=$env:BUILD_TYPE
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
-DVCPKG_TARGET_TRIPLET=x64-windows
-DUSE_VCPKG=ON
- 'echo "Step 4: Building main project"'
- echo "Building main project for Windows..."
- cmake --build . --config $env:BUILD_TYPE --parallel
- 'echo "Step 5: Deploying Qt dependencies"'
- 'echo "Deploying Qt dependencies using windeployqt..."'
- '$targetDir = "./$env:BUILD_TYPE"'
- 'echo "Target directory is ${targetDir}"'
- 'echo "Current working directory is $(Get-Location)"'
- 'echo "Listing contents of current directory:"'
- dir
- 'echo "Listing contents of target directory:"'
- 'if (Test-Path $targetDir) { dir $targetDir } else { echo "Target directory does not exist" }'
- 'echo "Checking for exe files in target directory:"'
- 'if (Test-Path "${targetDir}/*.exe") { dir "${targetDir}/*.exe" } else { echo "No exe files found in ${targetDir}" }'
- '$windeployqt = "$env:QT_BIN_DIR/windeployqt.exe"'
- 'echo "windeployqt path is ${windeployqt}"'
- |
if (Test-Path $windeployqt) {
echo "Found windeployqt, checking for exe files..."
$exeFiles = Get-ChildItem -Path $targetDir -Filter "*.exe" -ErrorAction SilentlyContinue
if ($exeFiles.Count -gt 0) {
echo "Found exe files, running windeployqt..."
foreach ($exe in $exeFiles) {
echo "Deploying Qt dependencies for $($exe.FullName)"
& $windeployqt --release --no-system-d3d-compiler --no-opengl-sw --no-angle $exe.FullName
}
} else {
echo "ERROR No exe files found in ${targetDir}"
echo "Contents of ${targetDir}:"
if (Test-Path $targetDir) { dir $targetDir } else { echo "Directory does not exist" }
}
} else {
echo "windeployqt not found at ${windeployqt}, copying Qt DLLs manually..."
# 确保目标目录存在
if (!(Test-Path $targetDir)) {
echo "Creating target directory ${targetDir}"
New-Item -ItemType Directory -Path $targetDir -Force
}
# vcpkg的Release DLLs可能直接在installed/x64-windows/bin下
$qtDllPath = "$env:QT_BIN_DIR"
# 如果tools/qt5/bin下没有DLL,尝试vcpkg的bin目录
if (!(Test-Path "$qtDllPath/Qt5Core.dll")) {
$qtDllPath = "$env:VCPKG_ROOT/installed/x64-windows/bin"
echo "Trying alternative Qt DLL path ${qtDllPath}"
}
if (Test-Path $qtDllPath) {
echo "Copying Qt DLLs from ${qtDllPath}"
Copy-Item "$qtDllPath/Qt5Core.dll" -Destination $targetDir -ErrorAction SilentlyContinue -Force
Copy-Item "$qtDllPath/Qt5Gui.dll" -Destination $targetDir -ErrorAction SilentlyContinue -Force
Copy-Item "$qtDllPath/Qt5Widgets.dll" -Destination $targetDir -ErrorAction SilentlyContinue -Force
Copy-Item "$qtDllPath/Qt5Network.dll" -Destination $targetDir -ErrorAction SilentlyContinue -Force
Copy-Item "$qtDllPath/Qt5SerialPort.dll" -Destination $targetDir -ErrorAction SilentlyContinue -Force
Copy-Item "$qtDllPath/Qt5Sql.dll" -Destination $targetDir -ErrorAction SilentlyContinue -Force
Copy-Item "$qtDllPath/Qt5Svg.dll" -Destination $targetDir -ErrorAction SilentlyContinue -Force
Copy-Item "$qtDllPath/Qt5Concurrent.dll" -Destination $targetDir -ErrorAction SilentlyContinue -Force
} else {
echo "ERROR Qt DLL path not found ${qtDllPath}"
}
}
- 'echo "Step 7: Copying Visual C++ runtime"'
- 'echo "Copying Visual C++ runtime..."'
- '$vcRedistPath = "C:/Program Files (x86)/Microsoft Visual Studio/2022/Enterprise/VC/Redist/MSVC/14.37.32822/x64/Microsoft.VC143.CRT"'
- |
if (Test-Path $vcRedistPath) {
Copy-Item "$vcRedistPath/*.dll" -Destination $targetDir -Force
} else {
echo "Warning VC Redist path not found ${vcRedistPath}"
}
- 'echo "Final verification of build artifacts..."'
- 'echo "Contents of Release directory:"'
- 'if (Test-Path $targetDir) { dir $targetDir } else { echo "Release directory not found" }'
- 'echo "Checking for devicelib.dll in Release directory:"'
- 'if (Test-Path "${targetDir}/devicelib.dll") { echo "devicelib.dll found in Release directory" } else { echo "devicelib.dll NOT found in Release directory" }'
- cd ..
artifacts:
name: "windows-build-$CI_COMMIT_SHORT_SHA"
paths:
- build-windows/Release/
- build-windows/*.dll
expire_in: 1 hour
# Windows平台打包任务
package_installer_windows:
stage: package
tags:
- windows-builder
rules:
# 在master分支且构建成功后触发
- if: $CI_COMMIT_BRANCH == "master"
when: on_success
# 在其他分支推送且构建成功后触发
- if: $CI_PIPELINE_SOURCE == "push"
when: on_success
dependencies:
- build_project_windows
script:
- echo "Creating Windows installer package..."
- echo "Checking for NSIS..."
- |
if (Get-Command "makensis" -ErrorAction SilentlyContinue) {
echo "Found NSIS, creating installer..."
echo "Current directory: $(Get-Location)"
echo "Listing installer files:"
dir *.nsi -ErrorAction SilentlyContinue
if (Test-Path "installer.nsi") {
echo "Building NSIS installer..."
makensis installer.nsi
echo "Installer creation completed"
dir *.exe -ErrorAction SilentlyContinue
} else {
echo "ERROR: installer.nsi not found"
dir
}
} else {
echo "ERROR: NSIS (makensis) not found in PATH"
echo "Available commands:"
Get-Command make* -ErrorAction SilentlyContinue
}
- echo "Creating ZIP package as backup..."
- $zipName = "xxxx-Windows-x64-$env:CI_COMMIT_SHORT_SHA.zip"
- Compress-Archive -Path "build-windows/Release/*" -DestinationPath $zipName -Force
- echo "Package creation completed"
artifacts:
name: "windows-installer-$CI_COMMIT_SHORT_SHA"
paths:
- "*.exe" # Windows安装程序
- "*Windows*.zip" # Windows ZIP包
expire_in: 1 week
# 为将来的Linux构建预留模板
.linux_build_template: &linux_build_template
stage: build
before_script:
- echo "Building on Linux platform"
- export VCPKG_ROOT="/opt/vcpkg"
- export QT_DIR="/opt/Qt/5.15.2/gcc_64"
- export PATH="$VCPKG_ROOT:$QT_DIR/bin:$PATH"
- mkdir -p build-linux
script:
- echo "Linux build steps will be implemented here"
artifacts:
name: "linux-build-$CI_COMMIT_SHORT_SHA"
paths:
- build-linux/
expire_in: 1 hour
# 示例:Ubuntu构建任务(暂时禁用)
build_project_ubuntu:
<<: *linux_build_template
tags:
- linux
- ubuntu
rules:
- if: "$CI_RUNNER_TAGS =~ /ubuntu/"
when: manual # 手动触发,直到配置完成
script:
- echo "Ubuntu build not yet implemented"
上面的策略是只要提交代码就自动编译,其实应该是tag版本的时候才触发编译。
下面是我的cmakelists.txt里面的部分内容:
cmake_minimum_required(VERSION 3.16)
project(xxxx VERSION 1.0.0 LANGUAGES CXX)
# 添加选项用于切换环境
option(USE_VCPKG "Use vcpkg instead of MSYS2 MinGW64" OFF)
# 定义路径变量,便于维护
if(WIN32)
# Windows平台路径
if(USE_VCPKG)
# 优先使用环境变量,如果没有则使用默认值
if(DEFINED ENV{VCPKG_ROOT})
set(VCPKG_ROOT_DIR "$ENV{VCPKG_ROOT}")
message(STATUS "Using VCPKG_ROOT from environment: ${VCPKG_ROOT_DIR}")
elseif(DEFINED VCPKG_ROOT_DIR)
# 使用CMake命令行传入的值
message(STATUS "Using VCPKG_ROOT from CMake variable: ${VCPKG_ROOT_DIR}")
else()
# 默认路径
set(VCPKG_ROOT_DIR "D:/vcpkg/vcpkg")
message(STATUS "Using default VCPKG_ROOT: ${VCPKG_ROOT_DIR}")
endif()
# 设置vcpkg相关路径
set(VCPKG_INSTALLED_DIR "${VCPKG_ROOT_DIR}/installed/x64-windows")
message(STATUS "Forcing VCPKG_INSTALLED_DIR to: ${VCPKG_INSTALLED_DIR}")
set(VCPKG_TOOLS_DIR "${VCPKG_INSTALLED_DIR}/tools/qt5")
set(VCPKG_SCRIPTS_DIR "${VCPKG_ROOT_DIR}/scripts")
endif()
# MSYS2路径设置
set(MSYS2_ROOT_DIR "D:/msys64")
set(MSYS2_MINGW64_DIR "${MSYS2_ROOT_DIR}/mingw64")
set(MSYS2_USR_DIR "${MSYS2_ROOT_DIR}/usr")
endif()
if(UNIX)
# UNIX平台路径
set(VCPKG_ROOT_DIR "/data/cpp/vcpkg")
set(VCPKG_SCRIPTS_DIR "${VCPKG_ROOT_DIR}/scripts")
# 检测系统架构
execute_process(
COMMAND uname -m
OUTPUT_VARIABLE SYSTEM_ARCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# 根据检测到的架构设置对应的目录
if(SYSTEM_ARCH STREQUAL "x86_64")
set(VCPKG_TRIPLET "x64-linux")
elseif(SYSTEM_ARCH STREQUAL "i686")
set(VCPKG_TRIPLET "x86-linux")
elseif(SYSTEM_ARCH STREQUAL "aarch64")
set(VCPKG_TRIPLET "arm64-linux")
elseif(SYSTEM_ARCH STREQUAL "armv7l")
set(VCPKG_TRIPLET "arm-linux")
elseif(SYSTEM_ARCH STREQUAL "loongarch64")
set(VCPKG_TRIPLET "loongarch64-linux")
else()
# 默认使用x64-linux
message(WARNING "未知架构: ${SYSTEM_ARCH},使用默认的x64-linux triplet")
set(VCPKG_TRIPLET "x64-linux")
endif()
# 设置安装目录路径
set(VCPKG_INSTALLED_DIR "${VCPKG_ROOT_DIR}/installed/${VCPKG_TRIPLET}")
set(VCPKG_TOOLS_DIR "${VCPKG_INSTALLED_DIR}/tools/qt5")
set(VCPKG_SCRIPTS_DIR "${VCPKG_ROOT_DIR}/scripts")
message(STATUS "使用VCPKG triplet: ${VCPKG_TRIPLET}")
endif()
message(STATUS "VCPKG_INSTALLED_DIR: ${VCPKG_INSTALLED_DIR}")
message(STATUS "VCPKG_TOOLS_DIR: ${VCPKG_TOOLS_DIR}")
message(STATUS "VCPKG_SCRIPTS_DIR: ${VCPKG_SCRIPTS_DIR}")
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(QUAZIP_QT_MAJOR_VERSION 5)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static libraries" FORCE)
set(QUAZIP_BZIP2 OFF CACHE BOOL "Disable BZIP2 compression" FORCE)
set(QUAZIP_USE_QT_ZLIB OFF CACHE BOOL "Use Qt ZLIB" FORCE)
gitlab ci/cd文件里面指定了编译的时候设置 -DUSE_VCPKG=ON ,然后yml里面在 before_script:的部分设置了VCPKG的环境变量值。
最后是打包脚本installer.nsi的内容:
# xxxx NSIS 安装脚本
# 编码: UTF-8
!define PRODUCT_NAME "xxxxx"
!define PRODUCT_VERSION "1.0.0"
!define PRODUCT_PUBLISHER "xxxx Technology"
!define PRODUCT_WEB_SITE "https://www.xxxxx"
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\xxxxx.exe"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir"
# 设置安装程序属性
Name "${PRODUCT_NAME}"
OutFile "xxx-Setup.exe"
InstallDir "$PROGRAMFILES\xxxx"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
ShowUnInstDetails show
RequestExecutionLevel admin
Unicode True
# 现代UI设置
!include "MUI2.nsh"
!include "FileFunc.nsh"
!include "LogicLib.nsh"
!include "nsProcess.nsh"
# UI配置
!define MUI_ABORTWARNING
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
# 安装页面
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
# 开始菜单页面
Var StartMenuFolder
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${PRODUCT_NAME}"
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}"
!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder
!insertmacro MUI_PAGE_INSTFILES
# 完成页面
!define MUI_FINISHPAGE_RUN "$INSTDIR\xxxx.exe"
!define MUI_FINISHPAGE_RUN_TEXT "立即启动xxxx"
!define MUI_FINISHPAGE_SHOWREADME ""
!define MUI_FINISHPAGE_SHOWREADME_TEXT "开机自动启动"
!define MUI_FINISHPAGE_SHOWREADME_FUNCTION EnableAutoStart
!insertmacro MUI_PAGE_FINISH
# 卸载页面
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
# 语言文件
!insertmacro MUI_LANGUAGE "SimpChinese"
# 版本信息
VIProductVersion "1.0.0.0"
VIAddVersionKey /LANG=${LANG_SIMPCHINESE} "ProductName" "${PRODUCT_NAME}"
VIAddVersionKey /LANG=${LANG_SIMPCHINESE} "Comments" "xxxxx"
VIAddVersionKey /LANG=${LANG_SIMPCHINESE} "CompanyName" "${PRODUCT_PUBLISHER}"
VIAddVersionKey /LANG=${LANG_SIMPCHINESE} "LegalTrademarks" "${PRODUCT_NAME} 是 ${PRODUCT_PUBLISHER} 的商标"
VIAddVersionKey /LANG=${LANG_SIMPCHINESE} "LegalCopyright" "© ${PRODUCT_PUBLISHER}"
VIAddVersionKey /LANG=${LANG_SIMPCHINESE} "FileDescription" "${PRODUCT_NAME}"
VIAddVersionKey /LANG=${LANG_SIMPCHINESE} "FileVersion" "${PRODUCT_VERSION}"
VIAddVersionKey /LANG=${LANG_SIMPCHINESE} "ProductVersion" "${PRODUCT_VERSION}"
# 检查进程函数
Function CheckAndKillProcess
StrCpy $1 "xxxx.exe"
nsProcess::_FindProcess "$1"
Pop $R0
${If} $R0 = 0
MessageBox MB_YESNO|MB_ICONQUESTION "检测到xxxx正在运行,需要关闭才能继续安装。是否立即关闭?" IDYES KillProcess IDNO AbortInstall
KillProcess:
DetailPrint "正在关闭xxxx..."
nsProcess::_KillProcess "$1"
Pop $R0
Sleep 2000
# 再次检查进程是否已关闭
nsProcess::_FindProcess "$1"
Pop $R0
${If} $R0 = 0
MessageBox MB_OK|MB_ICONSTOP "无法关闭xxxx,请手动关闭后重新运行安装程序。"
Abort
${EndIf}
DetailPrint "xxxx已关闭"
Goto ContinueInstall
AbortInstall:
Abort
ContinueInstall:
${EndIf}
FunctionEnd
# 开机自动启动函数
Function EnableAutoStart
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "${PRODUCT_NAME}" "$INSTDIR\xxxx.exe"
DetailPrint "已设置开机自动启动"
FunctionEnd
# 安装程序初始化
Function .onInit
# 检查管理员权限
UserInfo::GetAccountType
pop $0
${If} $0 != "admin"
MessageBox MB_ICONSTOP "此程序需要管理员权限才能安装,请右键选择$\"以管理员身份运行$\"。"
SetErrorLevel 740 # ERROR_ELEVATION_REQUIRED
Quit
${EndIf}
# 检查并关闭正在运行的进程
Call CheckAndKillProcess
FunctionEnd
Section "主程序" SEC01
SetOutPath "$INSTDIR"
SetOverwrite on
# 复制启动器程序(主入口)
File "build-windows\Release\xxxx.exe"
# 复制主程序文件
File "build-windows\Release\xxxx.exe"
# 复制动态库
File "build-windows\Release\xxxx.dll"
# 复制Qt依赖库
File "build-windows\Release\*.dll"
# 复制Qt平台插件
SetOutPath "$INSTDIR\platforms"
File /nonfatal "build-windows\Release\platforms\*.*"
# 复制Qt翻译文件
SetOutPath "$INSTDIR\translations"
File /nonfatal "build-windows\Release\translations\*.*"
# 复制Qt网络插件
SetOutPath "$INSTDIR\bearer"
File /nonfatal "build-windows\Release\bearer\*.*"
# 复制Qt图像格式插件
SetOutPath "$INSTDIR\imageformats"
File /nonfatal "build-windows\Release\imageformats\*.*"
# 复制Qt图标引擎插件
SetOutPath "$INSTDIR\iconengines"
File /nonfatal "build-windows\Release\iconengines\*.*"
# 复制Qt样式插件
SetOutPath "$INSTDIR\styles"
File /nonfatal "build-windows\Release\styles\*.*"
# 复制Qt通用插件目录
SetOutPath "$INSTDIR\plugins"
File /nonfatal /r "build-windows\Release\plugins\*.*"
# 复制Qt SQL驱动插件
SetOutPath "$INSTDIR\sqldrivers"
File /nonfatal "build-windows\Release\sqldrivers\*.*"
# 回到主目录
SetOutPath "$INSTDIR"
# 创建卸载程序
WriteUninstaller "$INSTDIR\uninst.exe"
SectionEnd
Section "开始菜单快捷方式" SEC02
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\${PRODUCT_NAME}.lnk" "$INSTDIR\xxxxx.exe"
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\卸载${PRODUCT_NAME}.lnk" "$INSTDIR\uninst.exe"
!insertmacro MUI_STARTMENU_WRITE_END
SectionEnd
Section "桌面快捷方式" SEC03
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\xxxx.exe"
SectionEnd
Section -AdditionalIcons
WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
!insertmacro MUI_STARTMENU_WRITE_END
SectionEnd
Section -Post
WriteUninstaller "$INSTDIR\uninst.exe"
WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\launch.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\launch.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
# 获取安装大小
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "EstimatedSize" "$0"
SectionEnd
# 卸载程序初始化
Function un.onInit
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "您确实要完全移除 $(^Name) 及其所有的组件?" IDYES +2
Abort
# 检查并关闭正在运行的进程
StrCpy $1 "xxxx.exe"
nsProcess::_FindProcess "$1"
Pop $R0
${If} $R0 = 0
MessageBox MB_YESNO|MB_ICONQUESTION "检测到设备采集服务正在运行,需要关闭才能继续卸载。是否立即关闭?" IDYES KillProcess IDNO AbortUninstall
KillProcess:
DetailPrint "正在关闭设备采集服务..."
nsProcess::_KillProcess "$1"
Pop $R0
Sleep 2000
Goto ContinueUninstall
AbortUninstall:
Abort
ContinueUninstall:
${EndIf}
FunctionEnd
Function un.onUninstSuccess
HideWindow
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从您的计算机中移除。"
FunctionEnd
Section Uninstall
# 删除开机自动启动
DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "${PRODUCT_NAME}"
# 删除文件
Delete "$INSTDIR\${PRODUCT_NAME}.url"
Delete "$INSTDIR\uninst.exe"
Delete "$INSTDIR\xxx.exe"
Delete "$INSTDIR\xxxx.exe"
Delete "$INSTDIR\xxx.dll"
Delete "$INSTDIR\*.dll"
# 删除Qt插件目录
RMDir /r "$INSTDIR\platforms"
RMDir /r "$INSTDIR\translations"
RMDir /r "$INSTDIR\bearer"
RMDir /r "$INSTDIR\imageformats"
RMDir /r "$INSTDIR\iconengines"
RMDir /r "$INSTDIR\styles"
RMDir /r "$INSTDIR\plugins"
RMDir /r "$INSTDIR\sqldrivers"
# 删除快捷方式
!insertmacro MUI_STARTMENU_GETFOLDER "Application" $StartMenuFolder
Delete "$SMPROGRAMS\$StartMenuFolder\卸载${PRODUCT_NAME}.lnk"
Delete "$SMPROGRAMS\$StartMenuFolder\Website.lnk"
Delete "$SMPROGRAMS\$StartMenuFolder\${PRODUCT_NAME}.lnk"
RMDir "$SMPROGRAMS\$StartMenuFolder"
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
RMDir "$INSTDIR"
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
SetAutoClose true
SectionEnd
至此,你只要push代码到gitlab仓库以后就可以自动按照Release方式编译你的程序及自动调用nsis编译你的打包脚本得到安装程序了。