Files
2026-10-17 20:42:15 -07:00

176 lines
7.3 KiB
PowerShell

param(
[string]$Config = "Release",
[switch]$Clean,
[switch]$Test,
[switch]$Package
)
$ErrorActionPreference = "Stop"
$root = $PSScriptRoot
$build = Join-Path $root "build"
if ($Clean -and (Test-Path $build)) { Remove-Item -Recurse -Force $build }
if (-not (Get-Command cl.exe -ErrorAction SilentlyContinue)) {
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (-not (Test-Path $vswhere)) { throw "vswhere.exe not found - install Visual Studio with the C++ workload" }
$vsPath = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if (-not $vsPath) { throw "no Visual Studio install with the C++ toolset" }
$vcvars = Join-Path $vsPath "VC\Auxiliary\Build\vcvars64.bat"
if (-not (Test-Path $vcvars)) { throw "vcvars64.bat not found under $vsPath" }
cmd /c "`"$vcvars`" && set" | ForEach-Object {
if ($_ -match '^([^=]+)=(.*)$') { Set-Item -Path "env:$($matches[1])" -Value $matches[2] }
}
if (-not (Get-Command cl.exe -ErrorAction SilentlyContinue)) { throw "vcvars64 did not put cl.exe on PATH" }
}
$tools = Join-Path $root ".tools"
function Get-File($url, $out, $sha) {
Write-Host "downloading $url"
$ProgressPreference = "SilentlyContinue"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $out
if (-not $sha) { return }
$stream = [IO.File]::OpenRead($out)
try { $hash = [BitConverter]::ToString([Security.Cryptography.SHA256]::Create().ComputeHash($stream)) -replace "-", "" }
finally { $stream.Dispose() }
if ($hash -ne $sha) {
Remove-Item -Force $out
throw "$url does not match its checksum"
}
}
function Expand-Zip($zip, $dir) {
Add-Type -AssemblyName System.IO.Compression.FileSystem
if (Test-Path $dir) { Remove-Item -Recurse -Force $dir }
[IO.Compression.ZipFile]::ExtractToDirectory($zip, $dir)
Remove-Item -Force $zip
}
function Find-Python {
$ErrorActionPreference = "Continue"
foreach ($candidate in @("py -3", "python")) {
$exe, $prefix = $candidate -split " ", 2
if (-not (Get-Command $exe -ErrorAction SilentlyContinue)) { continue }
$prefix = @($prefix | Where-Object { $_ })
$found = & $exe @prefix -c "import sys; print(sys.executable if sys.version_info >= (3, 8) else '')" 2>$null
if ($LASTEXITCODE -eq 0 -and $found) { return "$found".Trim() }
}
return $null
}
function Get-Python {
$portable = Join-Path $tools "python\python.exe"
if (Test-Path $portable) { return $portable }
$found = Find-Python
if ($found) { return $found }
Write-Host "Python not found, setting up a portable copy in .tools" -ForegroundColor Yellow
$dir = Join-Path $tools "python"
New-Item -ItemType Directory -Force -Path $dir | Out-Null
$zip = Join-Path $tools "python.zip"
Get-File "https://www.python.org/ftp/python/3.12.10/python-3.12.10-embed-amd64.zip" $zip "4ACBED6DD1C744B0376E3B1CF57CE906F9DC9E95E68824584C8099A63025A3C3"
Expand-Zip $zip $dir
Get-ChildItem $dir -Filter "python*._pth" | ForEach-Object { Add-Content -LiteralPath $_.FullName "import site" }
$getPip = Join-Path $tools "get-pip.py"
Get-File "https://bootstrap.pypa.io/get-pip.py" $getPip $null
$ErrorActionPreference = "Continue"
& $portable $getPip -q --no-warn-script-location --disable-pip-version-check
if ($LASTEXITCODE -ne 0) { throw "could not set up pip for the portable Python" }
Remove-Item -Force $getPip
return $portable
}
function Initialize-Protobuf($python) {
$ErrorActionPreference = "Continue"
& $python -c "import google.protobuf" 2>$null
if ($LASTEXITCODE -eq 0) { return }
Write-Host "installing the protobuf Python package" -ForegroundColor Yellow
& $python -m pip install -q --disable-pip-version-check --no-warn-script-location protobuf
if ($LASTEXITCODE -ne 0) { & $python -m pip install -q --disable-pip-version-check --no-warn-script-location --user protobuf }
if ($LASTEXITCODE -ne 0) { throw "could not install the protobuf Python package" }
}
function Get-Protoc {
$command = Get-Command protoc -ErrorAction SilentlyContinue
if ($command) { return $command.Source }
$portable = Join-Path $tools "protoc\bin\protoc.exe"
if (-not (Test-Path $portable)) {
Write-Host "protoc not found, downloading it into .tools" -ForegroundColor Yellow
New-Item -ItemType Directory -Force -Path $tools | Out-Null
$zip = Join-Path $tools "protoc.zip"
Get-File "https://github.com/protocolbuffers/protobuf/releases/download/v33.0/protoc-33.0-win64.zip" $zip "3742CD49C8B6BD78B6760540367EB0FF62FA70A1032E15DAFE131BFAF296986A"
Expand-Zip $zip (Join-Path $tools "protoc")
}
return $portable
}
function Initialize-Dotnet {
$env:DOTNET_NOLOGO = "1"
$env:DOTNET_GENERATE_ASPNET_CERTIFICATE = "false"
if (Get-Command dotnet -ErrorAction SilentlyContinue) { return }
$dir = Join-Path $tools "dotnet"
if (-not (Test-Path (Join-Path $dir "dotnet.exe"))) {
Write-Host ".NET SDK not found, installing it into .tools" -ForegroundColor Yellow
New-Item -ItemType Directory -Force -Path $tools | Out-Null
$script = Join-Path $tools "dotnet-install.ps1"
Get-File "https://dot.net/v1/dotnet-install.ps1" $script $null
& powershell -NoProfile -ExecutionPolicy Bypass -File $script -Channel LTS -InstallDir $dir -NoPath
Remove-Item -Force $script
if (-not (Test-Path (Join-Path $dir "dotnet.exe"))) { throw "could not install the .NET SDK" }
}
$env:DOTNET_ROOT = $dir
$env:PATH = "$dir;$env:PATH"
}
$python = Get-Python
Initialize-Protobuf $python
$protoc = Get-Protoc
New-Item -ItemType Directory -Force -Path $build | Out-Null
cmake -S "$root" -B "$build" -G Ninja "-DCMAKE_BUILD_TYPE=$Config" "-DPython3_EXECUTABLE=$python" "-DPROTOC_EXECUTABLE=$protoc"
if ($LASTEXITCODE -ne 0) { throw "cmake configure failed" }
cmake --build $build --parallel
if ($LASTEXITCODE -ne 0) { throw "build failed" }
$launcher = $true
try {
Initialize-Dotnet
} catch {
if ($Package) { throw }
Write-Host "$($_.Exception.Message), skipping the launcher" -ForegroundColor Yellow
$launcher = $false
}
if ($launcher) {
& cmd /c "`"$(Join-Path $root 'gui\build.bat')`""
if ($LASTEXITCODE -ne 0) { throw "launcher build failed" }
}
if ($Test) {
& (Join-Path $build "bin\capysr_tests.exe")
if ($LASTEXITCODE -ne 0) { throw "tests failed" }
}
if ($Package) {
$dist = Join-Path $build "dist\CapySR-win64"
if (Test-Path $dist) { Remove-Item -Recurse -Force $dist }
New-Item -ItemType Directory -Force -Path (Join-Path $dist "data") | Out-Null
Copy-Item (Join-Path $build "bin\capysr.exe") $dist
Copy-Item (Join-Path $build "bin\CapyLauncher.exe") $dist
foreach ($dir in "config", "resources", "launcher") {
Copy-Item -Recurse (Join-Path $root $dir) (Join-Path $dist $dir)
}
Copy-Item (Join-Path $root "data\freesr-data.json") (Join-Path $dist "data")
$zip = "$dist.zip"
if (Test-Path $zip) { Remove-Item -Force $zip }
Compress-Archive -Path "$dist\*" -DestinationPath $zip
Write-Host "packaged $zip"
}
Write-Host "built $build\bin\capysr.exe" -ForegroundColor Green
if ($launcher) { Write-Host "built $build\bin\CapyLauncher.exe" -ForegroundColor Green }