mirror of
https://github.com/phantomptr/ps5upload.git
synced 2026-10-19 02:20:02 -05:00
Pin v0.44 (sha256 4d06eab7...). Its crt/ and prospero-nid are identical to v0.43, so the vendored sdk-crt (+ ps5upload.patch) and the portable prospero-nid stay as they are; the helper, installer and elfldr build to the same code (only the build-id differs). v0.44 adds LLVM 23 to the candidate list, so the Makefile comment and Homebrew fallbacks move too. scripts/update-ps5-sdk.sh (make update-sdk): finds the latest release (or --tag), checks the zip, rewrites the pin, re-vendors prospero-nid and crt only when upstream changed them (stops if our crt patch no longer applies), moves the "SDK vX.Y" doc mentions and installs with install-ps5-sdk.sh, keeping the old SDK as a backup. --check only reports. The installer names its backups after the release they hold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
246 lines
12 KiB
PowerShell
246 lines
12 KiB
PowerShell
# install-windows.ps1 — one-shot dev environment bootstrap for Windows 11.
|
|
#
|
|
# Idempotent: safe to re-run.
|
|
#
|
|
# Installs (via winget where possible):
|
|
# - Node.js LTS
|
|
# - Rust (rustup-init)
|
|
# - Visual Studio 2022 Build Tools w/ C++ workload (MSVC + Windows SDK)
|
|
# - 7zip (used to extract the PS5 SDK zip in CI-clean way)
|
|
# - Microsoft Edge WebView2 Runtime (preinstalled on Win11; verified)
|
|
# - Repository-pinned PS5 Payload SDK (currently v0.44)
|
|
# → $env:USERPROFILE\ps5-payload-sdk
|
|
#
|
|
# Run from an elevated PowerShell:
|
|
# PS> Set-ExecutionPolicy -Scope Process Bypass -Force
|
|
# PS> .\scripts\install-windows.ps1
|
|
#
|
|
# After it finishes, the script prints the env exports you need to persist via
|
|
# `setx` (or just paste into the current shell) so `make build` and `make run-client`
|
|
# work in any new terminal — assuming you have GNU Make available (Git Bash, MSYS2,
|
|
# or `winget install ezwinports.make`). Tauri itself doesn't need Make on Windows;
|
|
# the Make targets are convenience wrappers that shell out to npm/cargo.
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
# Default installs to %USERPROFILE%\ps5-payload-sdk — user-writable, no admin
|
|
# needed. We deliberately do NOT read $env:PS5_PAYLOAD_SDK: that's the
|
|
# *build-time* SDK path and may point at somewhere the current user can't
|
|
# write to. Pass -SdkDir or set $env:PS5_SDK_INSTALL_DIR to change.
|
|
[string]$SdkDir = $(if ($env:PS5_SDK_INSTALL_DIR) { $env:PS5_SDK_INSTALL_DIR } else { Join-Path $env:USERPROFILE 'ps5-payload-sdk' }),
|
|
[string]$SdkTag = '',
|
|
[string]$SdkSha256 = ''
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Log { param($m) Write-Host "`n==> $m" -ForegroundColor Cyan }
|
|
function Ok { param($m) Write-Host "✓ $m" -ForegroundColor Green }
|
|
function Warn { param($m) Write-Host "! $m" -ForegroundColor Yellow }
|
|
function Die { param($m) Write-Host "ERROR: $m" -ForegroundColor Red; exit 1 }
|
|
|
|
function Has-Cmd { param($name) (Get-Command $name -ErrorAction SilentlyContinue) -ne $null }
|
|
|
|
# Load the same immutable SDK tag and release checksum used by the POSIX
|
|
# installer and GitHub Actions. Callers may override both parameters together
|
|
# for local experiments; release builds always use these repository values.
|
|
$repoRoot = Split-Path -Parent $PSScriptRoot
|
|
$sdkMetadataPath = Join-Path $PSScriptRoot 'ps5-sdk.env'
|
|
if (-not (Test-Path $sdkMetadataPath)) { Die "missing SDK metadata: $sdkMetadataPath" }
|
|
$sdkMetadata = @{}
|
|
Get-Content $sdkMetadataPath | ForEach-Object {
|
|
if ($_ -match '^([A-Z0-9_]+)=(.+)$') { $sdkMetadata[$Matches[1]] = $Matches[2].Trim() }
|
|
}
|
|
$pinnedSdkTag = $sdkMetadata['PS5_SDK_TAG']
|
|
$pinnedSdkSha256 = $sdkMetadata['PS5_SDK_SHA256']
|
|
if ($pinnedSdkTag -notmatch '^v\d+\.\d+(?:\.\d+)?$') {
|
|
Die 'PS5_SDK_TAG in scripts\ps5-sdk.env is invalid'
|
|
}
|
|
if ($pinnedSdkSha256 -notmatch '^[0-9a-f]{64}$') {
|
|
Die 'PS5_SDK_SHA256 in scripts\ps5-sdk.env must be a lowercase SHA-256'
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($SdkTag)) { $SdkTag = $pinnedSdkTag }
|
|
if ([string]::IsNullOrWhiteSpace($SdkSha256)) {
|
|
if ($SdkTag -ne $pinnedSdkTag) {
|
|
Die '-SdkSha256 is required when overriding -SdkTag'
|
|
}
|
|
$SdkSha256 = $pinnedSdkSha256
|
|
}
|
|
if ($SdkSha256 -notmatch '^[0-9a-fA-F]{64}$') { Die 'SDK SHA-256 must contain 64 hex characters' }
|
|
$SdkUrl = "https://github.com/ps5-payload-dev/sdk/releases/download/$SdkTag/ps5-payload-sdk.zip"
|
|
$sdkVersionMarker = '.ps5upload-sdk-version'
|
|
|
|
function Winget-Install {
|
|
param([string]$Id, [string]$Name, [string[]]$Override = @())
|
|
Log "winget install $Name ($Id)"
|
|
$args = @('install', '--id', $Id, '-e', '--accept-source-agreements', '--accept-package-agreements')
|
|
if ($Override.Count -gt 0) { $args += @('--override', ($Override -join ' ')) }
|
|
& winget @args
|
|
if ($LASTEXITCODE -ne 0 -and $LASTEXITCODE -ne -1978335189) {
|
|
# -1978335189 = APPINSTALLER_CLI_ERROR_PACKAGE_ALREADY_INSTALLED
|
|
Warn "winget exited $LASTEXITCODE for $Id (continuing — may already be installed)"
|
|
} else {
|
|
Ok "$Name installed (or already present)"
|
|
}
|
|
}
|
|
|
|
# ─── pre-flight ────────────────────────────────────────────────────────────────
|
|
if (-not [System.Environment]::OSVersion.VersionString.Contains('Windows')) {
|
|
Die "This script targets Windows. For Linux use scripts/install-ubuntu.sh; for macOS scripts/install-macos.sh."
|
|
}
|
|
if (-not (Has-Cmd winget)) {
|
|
Die "winget not found. Install 'App Installer' from the Microsoft Store, then re-run."
|
|
}
|
|
|
|
# ─── 1. Node.js LTS ────────────────────────────────────────────────────────────
|
|
if (Has-Cmd node) {
|
|
Ok "Node.js already installed: $(node --version)"
|
|
} else {
|
|
Winget-Install -Id 'OpenJS.NodeJS.LTS' -Name 'Node.js LTS'
|
|
}
|
|
|
|
# ─── 2. Rust toolchain ─────────────────────────────────────────────────────────
|
|
if ((Has-Cmd rustc) -and (Has-Cmd cargo)) {
|
|
Ok "Rust already installed: $(rustc --version)"
|
|
} else {
|
|
Log "Installing Rust via rustup-init"
|
|
$tmpDir = Join-Path $env:TEMP "rustup-$(Get-Random)"
|
|
New-Item -ItemType Directory -Path $tmpDir | Out-Null
|
|
$rustupExe = Join-Path $tmpDir 'rustup-init.exe'
|
|
Invoke-WebRequest -UseBasicParsing -Uri 'https://win.rustup.rs/x86_64' -OutFile $rustupExe
|
|
& $rustupExe -y --default-toolchain stable --profile default
|
|
if ($LASTEXITCODE -ne 0) { Die "rustup-init failed (exit $LASTEXITCODE)" }
|
|
Remove-Item $tmpDir -Recurse -Force
|
|
# Make cargo discoverable in this session
|
|
$env:Path = "$env:USERPROFILE\.cargo\bin;$env:Path"
|
|
Ok "Rust installed: $(rustc --version)"
|
|
}
|
|
|
|
# ─── 3. MSVC Build Tools (C++ workload) ────────────────────────────────────────
|
|
$vsWherePath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
|
$hasVcTools = $false
|
|
if (Test-Path $vsWherePath) {
|
|
$vsInstance = & $vsWherePath -products '*' -requires 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' -format json | ConvertFrom-Json
|
|
if ($vsInstance) { $hasVcTools = $true }
|
|
}
|
|
if ($hasVcTools) {
|
|
Ok "MSVC C++ Build Tools already installed"
|
|
} else {
|
|
Winget-Install -Id 'Microsoft.VisualStudio.2022.BuildTools' -Name 'VS 2022 Build Tools' `
|
|
-Override @('--quiet','--wait','--norestart','--nocache',
|
|
'--add Microsoft.VisualStudio.Workload.VCTools',
|
|
'--includeRecommended')
|
|
}
|
|
|
|
# ─── 4. WebView2 Runtime ───────────────────────────────────────────────────────
|
|
$webview2Path = 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}'
|
|
if (Test-Path $webview2Path) {
|
|
Ok "WebView2 Runtime already installed"
|
|
} else {
|
|
Winget-Install -Id 'Microsoft.EdgeWebView2Runtime' -Name 'WebView2 Runtime'
|
|
}
|
|
|
|
# ─── 5. 7zip (for clean SDK extraction) ────────────────────────────────────────
|
|
if (-not (Has-Cmd 7z)) {
|
|
Winget-Install -Id '7zip.7zip' -Name '7-Zip'
|
|
}
|
|
|
|
# ─── 5b. LLVM (prospero-clang dependency) ────────────────────────────────────
|
|
# The PS5 payload toolchain (prospero-clang + ld.lld) needs LLVM with
|
|
# lld included. Without this `make payload` fails on a fresh Windows
|
|
# checkout — the SDK ships its own clang shim but expects host lld to be
|
|
# discoverable. macOS discovers Homebrew's current llvm, Ubuntu pins 22; do the
|
|
# equivalent here. winget's LLVM.LLVM tracks latest, which is fine —
|
|
# prospero-clang is forward-compatible with newer host LLVM.
|
|
if (Has-Cmd clang) {
|
|
Ok "LLVM/clang already installed: $(clang --version | Select-Object -First 1)"
|
|
} else {
|
|
Winget-Install -Id 'LLVM.LLVM' -Name 'LLVM (clang + lld)'
|
|
# Make clang/lld discoverable in this session for any subsequent
|
|
# `make payload` step the user runs from the same shell.
|
|
$env:Path = "${env:ProgramFiles}\LLVM\bin;$env:Path"
|
|
}
|
|
|
|
# ─── 6. PS5 Payload SDK ────────────────────────────────────────────────────────
|
|
$prosperoMk = Join-Path $SdkDir 'toolchain\prospero.mk'
|
|
$versionMarkerPath = Join-Path $SdkDir $sdkVersionMarker
|
|
$installedSdkTag = if (Test-Path $versionMarkerPath) { (Get-Content $versionMarkerPath -Raw).Trim() } else { '' }
|
|
if ((Test-Path $prosperoMk) -and $installedSdkTag -eq $SdkTag) {
|
|
Ok "PS5 SDK $SdkTag already installed at $SdkDir"
|
|
} else {
|
|
Log "Downloading PS5 Payload SDK $SdkTag → $SdkDir"
|
|
$tmp = Join-Path $env:TEMP "ps5sdk-$(Get-Random)"
|
|
New-Item -ItemType Directory -Path $tmp | Out-Null
|
|
try {
|
|
$zip = Join-Path $tmp 'sdk.zip'
|
|
Invoke-WebRequest -UseBasicParsing -Uri $SdkUrl -OutFile $zip
|
|
$actualSha256 = (Get-FileHash -Algorithm SHA256 -Path $zip).Hash.ToLowerInvariant()
|
|
if ($actualSha256 -ne $SdkSha256.ToLowerInvariant()) {
|
|
Die "SDK checksum mismatch: expected $SdkSha256, got $actualSha256"
|
|
}
|
|
Ok "Verified official archive SHA-256 $actualSha256"
|
|
|
|
Expand-Archive -Path $zip -DestinationPath $tmp -Force
|
|
$extracted = Join-Path $tmp 'ps5-payload-sdk'
|
|
if (-not (Test-Path (Join-Path $extracted 'toolchain\prospero.mk'))) {
|
|
Die "SDK zip did not contain the expected ps5-payload-sdk\ toolchain"
|
|
}
|
|
if (-not (Test-Path (Join-Path $extracted 'target\lib\crt1.o'))) {
|
|
Die 'SDK zip is missing target\lib\crt1.o'
|
|
}
|
|
Set-Content -Path (Join-Path $extracted $sdkVersionMarker) -Value $SdkTag -Encoding ascii
|
|
|
|
$parent = Split-Path $SdkDir -Parent
|
|
if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent | Out-Null }
|
|
$backupDir = ''
|
|
if (Test-Path $SdkDir) {
|
|
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
|
$backupDir = "$SdkDir.backup-$stamp-$PID"
|
|
Move-Item -Path $SdkDir -Destination $backupDir
|
|
Ok "Moved the previous SDK to $backupDir"
|
|
}
|
|
try {
|
|
Move-Item -Path $extracted -Destination $SdkDir
|
|
} catch {
|
|
if ($backupDir -and (Test-Path $backupDir) -and -not (Test-Path $SdkDir)) {
|
|
Move-Item -Path $backupDir -Destination $SdkDir
|
|
}
|
|
throw
|
|
}
|
|
} finally {
|
|
if (Test-Path $tmp) { Remove-Item $tmp -Recurse -Force }
|
|
}
|
|
Ok "PS5 SDK $SdkTag installed at $SdkDir"
|
|
}
|
|
|
|
# ─── 7. client npm deps ────────────────────────────────────────────────────────
|
|
$clientDir = Join-Path $repoRoot 'client'
|
|
if (Test-Path $clientDir) {
|
|
Log "Installing client npm dependencies"
|
|
Push-Location $clientDir
|
|
try {
|
|
& npm install --no-audit --no-fund
|
|
if ($LASTEXITCODE -ne 0) { Die "npm install failed" }
|
|
Ok "client/node_modules ready"
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
}
|
|
|
|
# ─── 8. wrap up ────────────────────────────────────────────────────────────────
|
|
Write-Host ""
|
|
Write-Host "✓ Setup complete." -ForegroundColor Green
|
|
Write-Host ""
|
|
Write-Host "Persist PS5_PAYLOAD_SDK for future shells (run from any PowerShell):"
|
|
Write-Host " setx PS5_PAYLOAD_SDK `"$SdkDir`""
|
|
Write-Host ""
|
|
Write-Host "Then in this terminal (or open a new one):"
|
|
Write-Host " `$env:PS5_PAYLOAD_SDK = `"$SdkDir`""
|
|
Write-Host " make build"
|
|
Write-Host " make run-client"
|
|
Write-Host ""
|
|
Write-Host "Note: `make` is not part of Windows by default. If `make` isn't on PATH:"
|
|
Write-Host " winget install ezwinports.make"
|
|
Write-Host "or use Git Bash / MSYS2, where `make` is bundled."
|
|
Write-Host ""
|