174 lines
8.8 KiB
PowerShell
174 lines
8.8 KiB
PowerShell
<#
|
||
.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 }
|
||
}
|
||
}
|
||
|
||
# --- 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\)"
|
||
}
|