From 2b5b88924938aa53e7e2fd8274958f89ae4ff9ba Mon Sep 17 00:00:00 2001 From: patchzyy <64382339+patchzyy@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:58:50 +0200 Subject: [PATCH] Add windows CI --- Launcher/Build-Installer.ps1 | 7 +- Launcher/Prepare-Dependencies.ps1 | 196 ++++++++++++++++++++++++++++ Launcher/Prepare-NativePrebuilt.ps1 | 2 - THIRD-PARTY-NOTICES.md | 3 +- runtime/CMakeLists.txt | 6 + 5 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 Launcher/Prepare-Dependencies.ps1 diff --git a/Launcher/Build-Installer.ps1 b/Launcher/Build-Installer.ps1 index 9af45e1..75114df 100644 --- a/Launcher/Build-Installer.ps1 +++ b/Launcher/Build-Installer.ps1 @@ -94,12 +94,17 @@ if (-not (Test-Path -LiteralPath (Join-Path $portableTools 'llvm-mingw\bin\x86_6 } Assert-File (Join-Path $portableTools 'CMake\bin\cmake.exe') 'Portable CMake' Assert-File (Join-Path $portableTools 'Ninja\ninja.exe') 'Portable Ninja' -Assert-Directory $dependencySources 'Pinned offline dependency sources' # native_prebuilt carries the aurora/third-party archives the user no longer has # to compile (launcher/Prepare-NativePrebuilt.ps1). # Kept in step with InstalledLayout.DependencyNames by Test-PinnedFacts.ps1: the installed host # refuses to call a toolkit complete unless every one of these directories is present. $requiredDependencies = @('abseil-cpp','cppwinrt','dawn_prebuilt','fmt','freetype','imgui','libusb','native_prebuilt','png','SDL','sqlite3','tracy','xxhash','zlib','zstd') +$missingSources = @($requiredDependencies | Where-Object { $_ -ne 'native_prebuilt' } | + Where-Object { -not (Test-Path -LiteralPath (Join-Path $dependencySources $_) -PathType Container) }) +if ($missingSources.Count -gt 0) { + & (Join-Path $PSScriptRoot 'Prepare-Dependencies.ps1') -Destination $dependencySources +} +Assert-Directory $dependencySources 'Pinned offline dependency sources' # The precompiled archives are only interchangeable with what the user's machine # compiles if both came from this toolchain and this flag set, so a stale package diff --git a/Launcher/Prepare-Dependencies.ps1 b/Launcher/Prepare-Dependencies.ps1 new file mode 100644 index 0000000..ec80895 --- /dev/null +++ b/Launcher/Prepare-Dependencies.ps1 @@ -0,0 +1,196 @@ +# Populates Launcher/artifacts/dependencies: the pinned, unpatched upstream source trees (plus the +# prebuilt Dawn package and generated C++/WinRT headers) that Build-Installer.ps1 ships inside the +# installer so the user's build runs with FETCHCONTENT_FULLY_DISCONNECTED=ON. Every pin is the one +# aurora-main's own CMake declares; the Pin fields below are asserted against those files so the +# two cannot drift apart silently. native_prebuilt is not fetched here - Prepare-NativePrebuilt.ps1 +# compiles it from these trees. +[CmdletBinding()] +param( + [string]$Destination, + # Windows metadata source for cppwinrt.exe: 'local' (this machine's WinMetadata), 'sdk', or an + # installed SDK version such as 10.0.26100.0. + [string]$CppWinRtInput = 'local' +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version 3.0 + +$repoRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..')) +$auroraCMake = Join-Path $repoRoot 'aurora-main\CMakeLists.txt' +$auroraExtern = Join-Path $repoRoot 'aurora-main\extern\CMakeLists.txt' +$auroraDawn = Join-Path $repoRoot 'aurora-main\cmake\AuroraDawnProvider.cmake' +$auroraLibUsb = Join-Path $repoRoot 'aurora-main\cmake\AuroraLibUSB.cmake' +$auroraSdl = Join-Path $repoRoot 'aurora-main\cmake\AuroraSDL3Provider.cmake' + +# Name = directory under the destination; FetchContent maps it back through +# FETCHCONTENT_SOURCE_DIR_ (NativeBuildFlags.ps1), so the names are the declared +# FetchContent names, not the upstream project names. +$packages = @( + [pscustomobject]@{ + Name = 'SDL'; File = 'SDL3-3.4.4.tar.gz' + Uris = @('https://github.com/libsdl-org/SDL/releases/download/release-3.4.4/SDL3-3.4.4.tar.gz') + Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_SDL3_VERSION "3.4.4"' }, + @{ File = $auroraSdl; Text = 'releases/download/release-${AURORA_SDL3_VERSION}/SDL3-${AURORA_SDL3_VERSION}.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'abseil-cpp'; File = 'abseil-cpp-20240722.0.tar.gz' + Uris = @('https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'dawn_prebuilt'; File = 'dawn-v20260603.191052-windows-amd64.tar.gz' + Uris = @('https://github.com/encounter/dawn-build/releases/download/v20260603.191052/dawn-windows-amd64.tar.gz') + Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_DAWN_VERSION "v20260603.191052"' }, + @{ File = $auroraDawn; Text = 'SHA256=7785373d569b3b0237918ec9c523239f7d0667857c5ea8242e3cdfde95e6aeab' }) + }, + [pscustomobject]@{ + Name = 'fmt'; File = 'fmt-11.1.4.tar.gz' + Uris = @('https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'freetype'; File = 'freetype-2.14.3.tar.gz' + Uris = @('https://files.twilitrealm.dev/freetype-2.14.3.tar.gz', + 'https://download.savannah.gnu.org/releases/freetype/freetype-2.14.3.tar.gz', + 'https://downloads.sourceforge.net/project/freetype/freetype2/2.14.3/freetype-2.14.3.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://files.twilitrealm.dev/freetype-2.14.3.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'imgui'; File = 'imgui-1.91.9b-docking.tar.gz' + Uris = @('https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'libusb'; File = 'libusb-1.0.30.tar.bz2' + Uris = @('https://github.com/libusb/libusb/releases/download/v1.0.30/libusb-1.0.30.tar.bz2') + Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_LIBUSB_VERSION "1.0.30"' }, + @{ File = $auroraLibUsb; Text = 'releases/download/v${AURORA_LIBUSB_VERSION}/libusb-${AURORA_LIBUSB_VERSION}.tar.bz2' }) + }, + [pscustomobject]@{ + Name = 'png'; File = 'libpng-1.6.58.tar.gz' + Uris = @('https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.58.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.58.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'sqlite3'; File = 'sqlite-amalgamation-3510300.zip' + Uris = @('https://sqlite.org/2026/sqlite-amalgamation-3510300.zip') + Pins = @(@{ File = $auroraExtern; Text = 'https://sqlite.org/2026/sqlite-amalgamation-3510300.zip' }) + }, + [pscustomobject]@{ + Name = 'tracy'; File = 'tracy-a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz' + Uris = @('https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'xxhash'; File = 'xxHash-0.8.3.tar.gz' + Uris = @('https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.3.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.3.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'zlib'; File = 'zlib-1.3.2.tar.gz' + Uris = @('https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz' }) + }, + [pscustomobject]@{ + Name = 'zstd'; File = 'zstd-1.5.7.tar.gz' + Uris = @('https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz' }) + } +) + +# The C++/WinRT compiler (NuGet package = zip) that generates the projection headers. +$cppWinRtTool = [pscustomobject]@{ + Name = 'cppwinrt-tool'; File = 'Microsoft.Windows.CppWinRT.3.0.260818.1.nupkg' + Uris = @('https://www.nuget.org/api/v2/package/Microsoft.Windows.CppWinRT/3.0.260818.1') + Pins = @() +} + +if (-not $Destination) { $Destination = Join-Path $PSScriptRoot 'artifacts\dependencies' } +$Destination = [IO.Path]::GetFullPath($Destination) +$downloads = Join-Path $PSScriptRoot 'artifacts\downloads' +$tar = Join-Path $env:SystemRoot 'System32\tar.exe' +if (-not (Test-Path -LiteralPath $tar -PathType Leaf)) { throw "Windows archive tool is missing: $tar" } +[IO.Directory]::CreateDirectory($Destination) | Out-Null +[IO.Directory]::CreateDirectory($downloads) | Out-Null + +function Assert-Pinned($Package) { + foreach ($pin in $Package.Pins) { + if (-not (Test-Path -LiteralPath $pin.File -PathType Leaf)) { throw "Pin source is missing: $($pin.File)" } + $content = [IO.File]::ReadAllText($pin.File) + if (-not $content.Contains($pin.Text)) { + throw "$($Package.Name) is pinned to '$($pin.Text)' here but $($pin.File) no longer declares it; update both." + } + } +} + +function Get-Archive($Package) { + $archive = Join-Path $downloads $Package.File + if (Test-Path -LiteralPath $archive -PathType Leaf) { return $archive } + $temporary = $archive + '.partial' + $failures = @() + foreach ($uri in $Package.Uris) { + Remove-Item -LiteralPath $temporary -Force -ErrorAction SilentlyContinue + Write-Host "Downloading $($Package.Name) from $uri..." + try { + Invoke-WebRequest -UseBasicParsing -Uri $uri -OutFile $temporary + } catch { + $failures += "$uri ($($_.Exception.Message))" + continue + } + Move-Item -LiteralPath $temporary -Destination $archive -Force + return $archive + } + Remove-Item -LiteralPath $temporary -Force -ErrorAction SilentlyContinue + throw "$($Package.Name) could not be fetched: $($failures -join '; ')" +} + +function Expand-Package([string]$Archive, [string]$Target) { + # Release archives wrap everything in one versioned directory (SDL3-3.4.4/, tracy-/) while + # dawn-build's package is flat; either way the tree lands directly under the target. + $extract = Join-Path (Split-Path -Parent $Target) ('.extract-' + (Split-Path -Leaf $Target)) + if (Test-Path -LiteralPath $extract) { Remove-Item -LiteralPath $extract -Recurse -Force } + [IO.Directory]::CreateDirectory($extract) | Out-Null + # Symbolic links need a privilege Windows tar usually lacks; the only ones in these archives + # are zstd test aliases, and none are build inputs. + $listing = & $tar -tvf $Archive + if ($LASTEXITCODE -ne 0) { throw "Listing $Archive failed with exit code $LASTEXITCODE." } + $excludes = @($listing | ForEach-Object { if ($_ -match '^l.*\s(\S+)\s->\s') { '--exclude=' + $Matches[1] } }) + & $tar -xf $Archive -C $extract @excludes + if ($LASTEXITCODE -ne 0) { throw "Extracting $Archive failed with exit code $LASTEXITCODE." } + $entries = @(Get-ChildItem -LiteralPath $extract -Force) + $source = $extract + if ($entries.Count -eq 1 -and $entries[0].PSIsContainer) { $source = $entries[0].FullName } + if (Test-Path -LiteralPath $Target) { Remove-Item -LiteralPath $Target -Recurse -Force } + Move-Item -LiteralPath $source -Destination $Target + if (Test-Path -LiteralPath $extract) { Remove-Item -LiteralPath $extract -Recurse -Force } +} + +foreach ($package in $packages) { + Assert-Pinned $package + $target = Join-Path $Destination $package.Name + if (Test-Path -LiteralPath $target -PathType Container) { continue } + Expand-Package (Get-Archive $package) $target + Write-Host "Prepared $($package.Name)" +} + +$cppWinRt = Join-Path $Destination 'cppwinrt' +if (-not (Test-Path -LiteralPath (Join-Path $cppWinRt 'winrt\base.h') -PathType Leaf)) { + $toolRoot = Join-Path $PSScriptRoot 'artifacts\cppwinrt-tool' + $compiler = Join-Path $toolRoot 'bin\cppwinrt.exe' + if (-not (Test-Path -LiteralPath $compiler -PathType Leaf)) { + Expand-Package (Get-Archive $cppWinRtTool) $toolRoot + } + if (-not (Test-Path -LiteralPath $compiler -PathType Leaf)) { throw "cppwinrt.exe is missing: $compiler" } + if (Test-Path -LiteralPath $cppWinRt) { Remove-Item -LiteralPath $cppWinRt -Recurse -Force } + [IO.Directory]::CreateDirectory($cppWinRt) | Out-Null + Write-Host "Generating C++/WinRT headers (-input $CppWinRtInput)..." + & $compiler -input $CppWinRtInput -output $cppWinRt + if ($LASTEXITCODE -ne 0) { throw "cppwinrt.exe failed with exit code $LASTEXITCODE." } + if (-not (Test-Path -LiteralPath (Join-Path $cppWinRt 'winrt\base.h') -PathType Leaf)) { + throw "cppwinrt.exe produced no winrt\base.h under $cppWinRt" + } + Copy-Item -LiteralPath (Join-Path $toolRoot 'LICENSE') -Destination (Join-Path $cppWinRt 'LICENSE.txt') + Write-Host 'Prepared cppwinrt' +} + +Write-Host "Pinned dependency sources ready: $Destination" diff --git a/Launcher/Prepare-NativePrebuilt.ps1 b/Launcher/Prepare-NativePrebuilt.ps1 index 10a36b6..2757565 100644 --- a/Launcher/Prepare-NativePrebuilt.ps1 +++ b/Launcher/Prepare-NativePrebuilt.ps1 @@ -61,8 +61,6 @@ Assert-File $windres 'Portable resource compiler' Assert-File $clangBinary 'Portable clang driver binary' Assert-Directory $dependencies 'Pinned offline dependency sources' Assert-Directory $auroraSource 'aurora-main source tree' -Assert-File (Join-Path $repoRoot 'generated\build_shards\shards.cmake') ` - 'Translator shard manifest (run the developer build once so runtime/ can configure)' if ($Parallel -le 0) { $Parallel = [Environment]::ProcessorCount } diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md index f1977e8..5682605 100644 --- a/THIRD-PARTY-NOTICES.md +++ b/THIRD-PARTY-NOTICES.md @@ -117,7 +117,8 @@ Source: . Full license text: These are pinned in `aurora-main/extern/CMakeLists.txt`, `aurora-main/CMakeLists.txt` and `aurora-main/cmake/AuroraDawnProvider.cmake`. They are not stored in this repository; the build downloads them, and release installers carry the resulting binaries. Their license texts are -included in the installer's `licenses/` folder. +included in the installer's `licenses/` folder. The Windows installer bundles the pinned source +trees themselves (fetched by `Launcher/Prepare-Dependencies.ps1`) so end-user builds run offline. | Component | Version | License | Upstream | | --- | --- | --- | --- | diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 642de5f..532da95 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -243,6 +243,12 @@ list(REMOVE_ITEM SOURCES ${MKW_BASE_PRODUCT_SOURCE} ${MKW_RETRO_REWIND_PRODUCT_S set(MKW_TRANSLATED_SHARD_MANIFEST "${CMAKE_CURRENT_LIST_DIR}/../generated/build_shards/shards.cmake" CACHE FILEPATH "Translator-owned aggregate shard manifest") +# The prebuilt export only needs the aurora/third-party closure configured above, so a +# packaging machine without a translation stops here instead of failing. +if(MKW_NATIVE_PREBUILT_EXPORT_DIR AND NOT EXISTS "${MKW_TRANSLATED_SHARD_MANIFEST}") + message(STATUS "No translator shard manifest; configuring the native prebuilt export only") + return() +endif() if(NOT EXISTS "${MKW_TRANSLATED_SHARD_MANIFEST}") message(FATAL_ERROR "Missing translator-owned shard manifest: ${MKW_TRANSLATED_SHARD_MANIFEST}. "