geopro/installer/build_installer.ps1

184 lines
9.3 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<#
.SYNOPSIS
Geopro Windows 安装包一键打包工具。
.DESCRIPTION
把已构建的 geopro_desktop 部署目录打包成单个 Inno Setup 安装程序:
1) stage —— 将 build/release/src/app 复制到 installer\staging剔除构建产物
CMakeFiles / *_autogen / *.pdb / *.log / *.cmake
2) deploy —— 在 staging 上跑 windeployqt 补齐 Qt 运行时缺件
D3Dcompiler_47 / opengl32sw / WebEngine QML / 各插件)。
自动绕过 ADS 卡死问题qt6advanceddocking.dll 被误判为 Qt 模块)。
3) redist —— 确保 VC++ 运行时安装器 vc_redist.x64.exe 就位(缺则从 VS 复制)
4) compile —— 调用 ISCC 编译 geopro.iss输出到 installer\dist\
工具链Qt / ISCC / VS 的 vc_redist全部自动定位便于换机复用。
.PARAMETER Version
产品版本号(默认 3.0.0。最终文件名为 Geopro_Setup_<Version>-<yyyyMMdd>.exe。
.PARAMETER Rebuild
先执行 build.bat rebuild 做一次干净重编,再打包。默认使用现有构建产物。
.PARAMETER SkipDeploy
跳过 windeployqt 步骤(仅当确认 staging 已补齐时使用,不推荐)。
.PARAMETER QtPrefix
Qt 安装前缀。默认从 CMakePresets.json 的 CMAKE_PREFIX_PATH 解析。
.EXAMPLE
powershell -ExecutionPolicy Bypass -File installer\build_installer.ps1
.EXAMPLE
powershell -ExecutionPolicy Bypass -File installer\build_installer.ps1 -Version 3.1.0 -Rebuild
#>
[CmdletBinding()]
param(
[string]$Version = '3.0.0',
[switch]$Rebuild,
[switch]$SkipDeploy,
[string]$QtPrefix
)
$ErrorActionPreference = 'Stop'
$InstallerDir = $PSScriptRoot
$RepoRoot = Split-Path $InstallerDir -Parent
$BuildAppDir = Join-Path $RepoRoot 'build\release\src\app'
$StageDir = Join-Path $InstallerDir 'staging'
$RedistDir = Join-Path $InstallerDir 'redist'
$DistDir = Join-Path $InstallerDir 'dist'
$IssFile = Join-Path $InstallerDir 'geopro.iss'
$ExeName = 'geopro_desktop.exe'
$BuildDate = Get-Date -Format 'yyyyMMdd'
function Info($m){ Write-Host "[pack] $m" -ForegroundColor Cyan }
function Warn($m){ Write-Host "[pack] $m" -ForegroundColor Yellow }
function Die($m){ Write-Host "[pack] ERROR: $m" -ForegroundColor Red; exit 1 }
# --- 0. 可选:干净重编 -------------------------------------------------------
if ($Rebuild) {
Info '执行 build.bat rebuild干净重编...'
& (Join-Path $RepoRoot 'build.bat') rebuild
if ($LASTEXITCODE -ne 0) { Die "build.bat rebuild 失败 (exit $LASTEXITCODE)" }
}
# --- 1. 定位 Qt / windeployqt ----------------------------------------------
if (-not $QtPrefix) {
$presets = Join-Path $RepoRoot 'CMakePresets.json'
if (Test-Path $presets) {
try {
$j = Get-Content $presets -Raw | ConvertFrom-Json
foreach ($p in $j.configurePresets) {
if ($p.cacheVariables.CMAKE_PREFIX_PATH) {
$QtPrefix = $p.cacheVariables.CMAKE_PREFIX_PATH; break
}
}
} catch { }
}
}
if (-not $QtPrefix) { $QtPrefix = 'D:/Qt/6.11.1/msvc2022_64' }
$QtBin = Join-Path ($QtPrefix -replace '/','\') 'bin'
$WinDeploy = Join-Path $QtBin 'windeployqt.exe'
# --- 2. 定位 ISCC -----------------------------------------------------------
$IsccCandidates = @(
"$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe",
"${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe",
"$env:ProgramFiles\Inno Setup 6\ISCC.exe"
)
$Iscc = $IsccCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $Iscc) { $Iscc = (Get-Command ISCC.exe -ErrorAction SilentlyContinue).Source }
if (-not $Iscc) {
Die '未找到 Inno Setup (ISCC.exe)。请先安装winget install --id JRSoftware.InnoSetup -e'
}
# --- 3. 校验构建产物 --------------------------------------------------------
$BuiltExe = Join-Path $BuildAppDir $ExeName
if (-not (Test-Path $BuiltExe)) {
Die "未找到构建产物 $BuiltExe`n请先构建build.bat app或加 -Rebuild 参数)"
}
Info "构建产物: $BuiltExe ($([math]::Round((Get-Item $BuiltExe).Length/1MB,2)) MB, 修改于 $((Get-Item $BuiltExe).LastWriteTime))"
# --- 4. stage复制部署目录、剔除构建产物 -----------------------------------
Info 'stage 部署副本(剔除 CMakeFiles / *_autogen / *.pdb / *.log / *.cmake...'
if (Test-Path $StageDir) { Remove-Item $StageDir -Recurse -Force }
New-Item -ItemType Directory -Force $StageDir | Out-Null
robocopy $BuildAppDir $StageDir /E `
/XD CMakeFiles geopro_desktop_autogen `
/XF *.pdb *.log cmake_install.cmake *.ilk *.exp `
/NFL /NDL /NJH /NJS /MT:8 | Out-Null
if ($LASTEXITCODE -ge 8) { Die "robocopy 失败 (exit $LASTEXITCODE)" }
# --- 5. windeployqt 补齐 Qt 运行时(绕过 ADS 卡死) -------------------------
if (-not $SkipDeploy) {
if (-not (Test-Path $WinDeploy)) { Die "未找到 windeployqt: $WinDeploy(用 -QtPrefix 指定 Qt 路径)" }
Info 'windeployqt 补齐 Qt 运行时缺件...'
# qt6advanceddocking.dll 名字带 qt6 前缀windeployqt 会误当 Qt 模块去 Qt\bin 找它并报错中止。
# 临时把它拷进 Qt\bin 让 windeployqt 能读其依赖(实为 Qt6Core/Gui/Widgets跑完即删。
$adsName = 'qt6advanceddocking.dll'
$adsTmp = Join-Path $QtBin $adsName
$adsPreexisted = Test-Path $adsTmp
if (-not $adsPreexisted) { Copy-Item (Join-Path $StageDir $adsName) $adsTmp -Force }
try {
& $WinDeploy --release --no-translations --compiler-runtime (Join-Path $StageDir $ExeName) | Out-Null
if ($LASTEXITCODE -ne 0) { Die "windeployqt 失败 (exit $LASTEXITCODE)" }
} finally {
if (-not $adsPreexisted) { Remove-Item $adsTmp -Force -ErrorAction SilentlyContinue }
}
# 中文化windeployqt --no-translations 不带翻译,单独拷 Qt 自带 zh_CNQMessageBox/QFileDialog
# 等标准按钮中文化app 启动按 exe 旁 translations\ 加载)。
$qtZh = Join-Path $QtBin '..\translations\qtbase_zh_CN.qm'
if (Test-Path $qtZh) {
$stageTr = Join-Path $StageDir 'translations'
New-Item -ItemType Directory -Force $stageTr | Out-Null
Copy-Item $qtZh $stageTr -Force
} else {
Warn "未找到 qtbase_zh_CN.qm$qtZh)—部署版标准按钮可能仍为英文"
}
}
# --- 5.5 随包数据:本地样本演示数据 + PROJ 数据exe 旁布局,运行时相对定位)-------
# 客户端启动会同步加载本地样本数据构建工作台PROJ 数据供 3D 体素 CRS 配准。
# 二者缺失会导致登录后无界面/3D 退化,故随包到 exe 旁sampledata\ 与 proj\)。
Info '随包数据:复制样本演示数据 + PROJ 数据到 staging...'
# 用目录内 ASCII 标志文件 dem.tif 定位样本目录,避免在脚本里写中文路径(编码风险)。
$sampleSrc = Get-ChildItem (Join-Path $RepoRoot 'docs') -Directory -ErrorAction SilentlyContinue |
Where-Object { Test-Path (Join-Path $_.FullName 'dem.tif') } | Select-Object -First 1
if (-not $sampleSrc) { Die '未找到本地样本数据目录docs 下含 dem.tif 的目录)' }
robocopy $sampleSrc.FullName (Join-Path $StageDir 'sampledata') /E /NFL /NDL /NJH /NJS /MT:8 | Out-Null
if ($LASTEXITCODE -ge 8) { Die "robocopy 样本数据失败 (exit $LASTEXITCODE)" }
$projSrc = Join-Path $RepoRoot 'build\release\vcpkg_installed\x64-windows\share\proj'
if (-not (Test-Path (Join-Path $projSrc 'proj.db'))) { Die "未找到 PROJ 数据: $projSrc\proj.db" }
robocopy $projSrc (Join-Path $StageDir 'proj') /E /NFL /NDL /NJH /NJS /MT:8 | Out-Null
if ($LASTEXITCODE -ge 8) { Die "robocopy PROJ 数据失败 (exit $LASTEXITCODE)" }
# --- 6. VC++ 运行时安装器就位 -----------------------------------------------
New-Item -ItemType Directory -Force $RedistDir | Out-Null
$VcRedist = Join-Path $RedistDir 'vc_redist.x64.exe'
if (-not (Test-Path $VcRedist)) {
Info 'vc_redist.x64.exe 缺失,从 Visual Studio 复制...'
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$vsPath = & $vswhere -all -prerelease -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath | Select-Object -Last 1
$found = Get-ChildItem (Join-Path $vsPath 'VC\Redist') -Filter 'vc_redist.x64.exe' -Recurse -ErrorAction SilentlyContinue |
Sort-Object FullName -Descending | Select-Object -First 1
if (-not $found) { Die '未找到 vc_redist.x64.exe请手动放入 installer\redist\' }
Copy-Item $found.FullName $VcRedist -Force
}
# --- 7. ISCC 编译 -----------------------------------------------------------
New-Item -ItemType Directory -Force $DistDir | Out-Null
$stageMB = [math]::Round((Get-ChildItem $StageDir -Recurse -File | Measure-Object Length -Sum).Sum/1MB,1)
Info "staging 载荷 $stageMB MB开始用 Inno Setup 编译安装包..."
& $Iscc "/DAppVersion=$Version" "/DBuildDate=$BuildDate" $IssFile
if ($LASTEXITCODE -ne 0) { Die "ISCC 编译失败 (exit $LASTEXITCODE)" }
# --- 8. 收尾报告 ------------------------------------------------------------
$out = Join-Path $DistDir "Geopro_Setup_$Version-$BuildDate.exe"
if (Test-Path $out) {
Info '打包完成 ✓'
Write-Host " 安装包: $out"
Write-Host " 大小 : $([math]::Round((Get-Item $out).Length/1MB,1)) MB"
} else {
Warn "ISCC 返回成功,但未找到预期产物 $out(检查 installer\dist\"
}