2026-05-06 19:43:16 -04:00
|
|
|
param(
|
|
|
|
|
[string]$Version = "",
|
|
|
|
|
[string]$BuildDir = "build\win",
|
|
|
|
|
[string]$StagingDir = "dist\win",
|
2026-05-06 19:47:20 -04:00
|
|
|
[string]$WintunVersion = "0.14.1",
|
2026-05-06 19:43:16 -04:00
|
|
|
[switch]$Sign,
|
|
|
|
|
[string]$SignCert = ""
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
|
|
|
|
|
|
# Color output functions
|
|
|
|
|
function Write-Info { Write-Host $args -ForegroundColor Cyan }
|
|
|
|
|
function Write-Success { Write-Host $args -ForegroundColor Green }
|
|
|
|
|
function Write-Error { Write-Host $args -ForegroundColor Red }
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
Write-Info "=== DragonMoonlight Windows Installer Build ==="
|
|
|
|
|
|
|
|
|
|
# Determine version
|
|
|
|
|
if ([string]::IsNullOrEmpty($Version)) {
|
|
|
|
|
Write-Info "Version not provided, attempting git describe..."
|
|
|
|
|
try {
|
|
|
|
|
$Version = git describe --tags --abbrev=0 2>$null
|
|
|
|
|
if ([string]::IsNullOrEmpty($Version)) {
|
|
|
|
|
$Version = "0.1.0"
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
$Version = "0.1.0"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Write-Success "Building DragonMoonlight version: $Version"
|
|
|
|
|
|
|
|
|
|
# Check prerequisites
|
|
|
|
|
Write-Info "Checking prerequisites..."
|
|
|
|
|
$prerequisites = @("cmake", "cargo", "iscc", "windeployqt")
|
|
|
|
|
foreach ($tool in $prerequisites) {
|
|
|
|
|
try {
|
|
|
|
|
if ($tool -eq "iscc") {
|
|
|
|
|
$result = Get-Command "iscc.exe" -ErrorAction Stop
|
|
|
|
|
} elseif ($tool -eq "windeployqt") {
|
|
|
|
|
$result = Get-Command "windeployqt.exe" -ErrorAction Stop
|
|
|
|
|
} else {
|
|
|
|
|
$result = Get-Command $tool -ErrorAction Stop
|
|
|
|
|
}
|
|
|
|
|
Write-Success "✓ $tool found"
|
|
|
|
|
} catch {
|
|
|
|
|
Write-Error "✗ $tool not found. Please install it before proceeding."
|
|
|
|
|
throw "Missing prerequisite: $tool"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Build boringtun
|
|
|
|
|
Write-Info "Building boringtun..."
|
|
|
|
|
& pwsh scripts\build-boringtun-win.ps1
|
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
|
|
|
throw "boringtun build failed"
|
|
|
|
|
}
|
|
|
|
|
Write-Success "boringtun built successfully"
|
|
|
|
|
|
|
|
|
|
# CMake configure
|
|
|
|
|
Write-Info "Running CMake configure..."
|
2026-05-06 19:47:20 -04:00
|
|
|
cmake -B $BuildDir -A x64 -DCMAKE_BUILD_TYPE=Release
|
2026-05-06 19:43:16 -04:00
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
|
|
|
throw "CMake configure failed"
|
|
|
|
|
}
|
|
|
|
|
Write-Success "CMake configure completed"
|
|
|
|
|
|
|
|
|
|
# CMake build
|
|
|
|
|
Write-Info "Building with CMake..."
|
|
|
|
|
cmake --build $BuildDir --config Release
|
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
|
|
|
throw "CMake build failed"
|
|
|
|
|
}
|
|
|
|
|
Write-Success "CMake build completed"
|
|
|
|
|
|
|
|
|
|
# Create staging directory and copy executable
|
|
|
|
|
Write-Info "Staging release files..."
|
|
|
|
|
if (-not (Test-Path $StagingDir)) {
|
|
|
|
|
New-Item -ItemType Directory -Path $StagingDir -Force | Out-Null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$exePath = Join-Path $BuildDir "Release\DragonMoonlight.exe"
|
|
|
|
|
if (-not (Test-Path $exePath)) {
|
|
|
|
|
throw "DragonMoonlight.exe not found at $exePath"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Copy-Item -Path $exePath -Destination $StagingDir -Force
|
|
|
|
|
Write-Success "Copied DragonMoonlight.exe to $StagingDir"
|
|
|
|
|
|
|
|
|
|
# Run windeployqt
|
|
|
|
|
Write-Info "Running windeployqt..."
|
|
|
|
|
$stagedExe = Join-Path $StagingDir "DragonMoonlight.exe"
|
|
|
|
|
windeployqt --release --qmldir app $stagedExe
|
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
|
|
|
throw "windeployqt failed"
|
|
|
|
|
}
|
|
|
|
|
Write-Success "windeployqt completed"
|
|
|
|
|
|
|
|
|
|
# Download wintun.dll
|
|
|
|
|
Write-Info "Downloading Wintun..."
|
2026-05-06 19:47:20 -04:00
|
|
|
$wintunUrl = "https://www.wintun.net/builds/wintun-$WintunVersion.zip"
|
2026-05-06 19:43:16 -04:00
|
|
|
$tempDir = Join-Path $env:TEMP "wintun_build"
|
|
|
|
|
if (-not (Test-Path $tempDir)) {
|
|
|
|
|
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 19:47:20 -04:00
|
|
|
$wintunZip = Join-Path $tempDir "wintun-$WintunVersion.zip"
|
2026-05-06 19:43:16 -04:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
Write-Info "Downloading from $wintunUrl..."
|
|
|
|
|
Invoke-WebRequest -Uri $wintunUrl -OutFile $wintunZip -UseBasicParsing
|
|
|
|
|
|
|
|
|
|
Write-Info "Extracting wintun.dll..."
|
|
|
|
|
Expand-Archive -Path $wintunZip -DestinationPath $tempDir -Force
|
|
|
|
|
|
|
|
|
|
$wintunDll = Join-Path $tempDir "wintun\bin\amd64\wintun.dll"
|
|
|
|
|
if (-not (Test-Path $wintunDll)) {
|
|
|
|
|
throw "wintun.dll not found in extracted archive"
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 19:47:20 -04:00
|
|
|
# Verify wintun.dll size sanity check (x64 is ~50-80 KB)
|
|
|
|
|
$actualSize = (Get-Item $wintunDll).Length
|
|
|
|
|
if ($actualSize -lt 30000 -or $actualSize -gt 200000) {
|
|
|
|
|
throw "wintun.dll size check failed ($actualSize bytes) — download may be corrupt or tampered"
|
|
|
|
|
}
|
|
|
|
|
Write-Info "wintun.dll verified ($actualSize bytes)"
|
|
|
|
|
|
2026-05-06 19:43:16 -04:00
|
|
|
Copy-Item -Path $wintunDll -Destination $StagingDir -Force
|
|
|
|
|
Write-Success "Wintun.dll extracted and copied to $StagingDir"
|
|
|
|
|
} finally {
|
|
|
|
|
if (Test-Path $wintunZip) {
|
|
|
|
|
Remove-Item -Path $wintunZip -Force
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Run Inno Setup
|
|
|
|
|
Write-Info "Building installer with Inno Setup..."
|
|
|
|
|
|
|
|
|
|
$issArgs = @("/DMyAppVersion=$Version", "scripts\DragonMoonlight.iss")
|
|
|
|
|
|
|
|
|
|
if ($Sign -or -not [string]::IsNullOrEmpty($SignCert)) {
|
|
|
|
|
$cert = $SignCert
|
|
|
|
|
if ([string]::IsNullOrEmpty($cert) -and -not [string]::IsNullOrEmpty($env:SIGNTOOL_CERT)) {
|
|
|
|
|
$cert = $env:SIGNTOOL_CERT
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (-not [string]::IsNullOrEmpty($cert)) {
|
|
|
|
|
Write-Info "Code signing enabled with certificate: $cert"
|
|
|
|
|
$env:SIGNTOOL_CERT = $cert
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iscc @issArgs
|
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
|
|
|
throw "Inno Setup build failed"
|
|
|
|
|
}
|
|
|
|
|
Write-Success "Inno Setup build completed"
|
|
|
|
|
|
|
|
|
|
# Report results
|
|
|
|
|
$outputExe = Join-Path "dist" "DragonMoonlight-$Version-Setup.exe"
|
|
|
|
|
if (Test-Path $outputExe) {
|
|
|
|
|
Write-Success "Installer created: $outputExe"
|
|
|
|
|
|
|
|
|
|
$sha256 = (Get-FileHash -Path $outputExe -Algorithm SHA256).Hash
|
|
|
|
|
Write-Success "SHA256: $sha256"
|
|
|
|
|
|
|
|
|
|
Write-Info "Installer build successful!"
|
|
|
|
|
} else {
|
|
|
|
|
throw "Installer file not found at expected location: $outputExe"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch {
|
|
|
|
|
Write-Error "Build failed: $_"
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
finally {
|
|
|
|
|
# Clean up temporary files
|
|
|
|
|
$tempDir = Join-Path $env:TEMP "wintun_build"
|
|
|
|
|
if (Test-Path $tempDir) {
|
|
|
|
|
Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
|
|
|
}
|
|
|
|
|
}
|