mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-10-22 06:07:43 -04:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b0e42d623d | |||
| 6a1fa79bf6 | |||
| e1157b26a0 | |||
| 4f90ae9c51 | |||
| e8ca27223c |
@@ -21,7 +21,8 @@ param(
|
||||
# Discards every cache first. Used when a product was reported broken/blocked, so a possibly
|
||||
# corrupted translation or build directory can never contribute to the repaired product.
|
||||
[switch]$ForceCleanBuild,
|
||||
[int]$Parallel = 0
|
||||
[int]$Parallel = 0,
|
||||
[ValidateSet('v2', 'v3')] [string]$X86CpuProfile = 'v3'
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
@@ -397,11 +398,14 @@ try {
|
||||
$dependencies = Join-Path $Workspace 'Dependencies'
|
||||
$nativePrebuilt = Resolve-NativePrebuiltDirectory $dependencies $toolchainBin `
|
||||
(Join-Path $Workspace 'aurora-main') (Join-Path $Workspace 'runtime\third_party')
|
||||
if ($X86CpuProfile -eq 'v2') {
|
||||
Write-Host 'MKWCBUILD: This CPU does not support x86-64-v3; building for x86-64-v2'
|
||||
}
|
||||
$configure = Get-MkwNativeConfigureArguments `
|
||||
-SourceDirectory (Join-Path $Workspace 'runtime') -BuildDirectory $build `
|
||||
-Ninja $ninja -CCompiler $cc -CxxCompiler $cxx -ResourceCompiler $windres `
|
||||
-DependenciesDirectory $dependencies -NativePrebuiltDirectory $nativePrebuilt `
|
||||
-AdditionalArguments @("-DMKW_TRANSLATED_COMPILE_JOBS=$translatedJobs")
|
||||
-AdditionalArguments @("-DMKW_TRANSLATED_COMPILE_JOBS=$translatedJobs", "-DMKW_X86_CPU_PROFILE=$X86CpuProfile")
|
||||
Invoke-Checked $cmake $configure 'Configuring the bundled native toolchain' -StepId 'configure-native'
|
||||
if (-not [string]::IsNullOrWhiteSpace($NativeToolchainFingerprint)) {
|
||||
[ordered]@{ SchemaVersion = 1; NativeToolchainFingerprint = $NativeToolchainFingerprint } |
|
||||
|
||||
@@ -33,28 +33,33 @@ if (-not (Test-Path -LiteralPath $auroraCMake -PathType Leaf)) {
|
||||
$packages = @(
|
||||
[pscustomobject]@{
|
||||
Name = 'SDL'; File = 'SDL3-3.4.10.tar.gz'
|
||||
Sha256 = '12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785'
|
||||
Uris = @('https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz')
|
||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_SDL3_REF "refs/tags/release-3.4.10"' },
|
||||
@{ File = $auroraSdl; Text = 'URL "https://github.com/libsdl-org/SDL/archive/${AURORA_SDL3_REF}.tar.gz"' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'abseil-cpp'; File = 'abseil-cpp-20240722.0.tar.gz'
|
||||
Sha256 = 'f50e5ac311a81382da7fa75b97310e4b9006474f9560ac46f54a9967f07d4ae3'
|
||||
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-v20260807.225922-windows-amd64.tar.gz'
|
||||
Sha256 = '42a7a295c87b2e8a36312e2f84a5823aac63325e8e1d271bc7ced6f83bfb075f'
|
||||
Uris = @('https://github.com/encounter/dawn/releases/download/v20260807.225922/dawn-windows-amd64.tar.gz')
|
||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_DAWN_VERSION "v20260807.225922"' },
|
||||
@{ File = $auroraDawn; Text = 'SHA256=42a7a295c87b2e8a36312e2f84a5823aac63325e8e1d271bc7ced6f83bfb075f' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'fmt'; File = 'fmt-12.1.0.tar.gz'
|
||||
Sha256 = 'ea7de4299689e12b6dddd392f9896f08fb0777ac7168897a244a6d6085043fea'
|
||||
Uris = @('https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'freetype'; File = 'freetype-2.14.3.tar.gz'
|
||||
Sha256 = 'e61b31ab26358b946e767ed7eb7f4bb2e507da1cfefeb7a8861ace7fd5c899a1'
|
||||
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')
|
||||
@@ -62,42 +67,50 @@ $packages = @(
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'imgui'; File = 'imgui-1.91.9b-docking.tar.gz'
|
||||
Sha256 = '466fdef9b18de15f0bb6e288e3d00ffa3d82200ec458ce5e4f724a161d9528a5'
|
||||
Uris = @('https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz')
|
||||
Pins = @(@{ File = $auroraImgui; 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'
|
||||
Sha256 = 'fea36f34f9156400209595e300840767ab1a385ede1dc7ee893015aea9c6dbaf'
|
||||
Uris = @('https://github.com/libusb/libusb/releases/download/v1.0.30/libusb-1.0.30.tar.bz2')
|
||||
Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(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'
|
||||
Sha256 = 'a9d4df463d36a6e5f9c29bd6f4967312d17e996c1854f3511f833924eb1993cf'
|
||||
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'
|
||||
Sha256 = 'acb1e6f5d832484bf6d32b681e858c38add8b2acdfd42ac5df24b8afb46552b4'
|
||||
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-0.14.1.zip'
|
||||
Sha256 = '908f3a2917fa86a247abfcf85dcf04bad1db6986a4d40f94b70512f3e9e98d5b'
|
||||
Uris = @('https://github.com/wolfpld/tracy/archive/refs/tags/v0.14.1.zip')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/refs/tags/v0.14.1.zip' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'xxhash'; File = 'xxHash-0.8.4.tar.gz'
|
||||
Sha256 = '5738270935e7c3d38a79b3adf7c9692566ce7895a25f67de43ad52ab504acd32'
|
||||
Uris = @('https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'zlib'; File = 'zlib-ng-2.3.3.tar.gz'
|
||||
Sha256 = 'f9c65aa9c852eb8255b636fd9f07ce1c406f061ec19a2e7d508b318ca0c907d1'
|
||||
Uris = @('https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.3.3.tar.gz')
|
||||
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.3.3.tar.gz' })
|
||||
},
|
||||
[pscustomobject]@{
|
||||
Name = 'zstd'; File = 'zstd-1.5.7.tar.gz'
|
||||
Sha256 = 'eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3'
|
||||
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' })
|
||||
}
|
||||
@@ -106,6 +119,7 @@ $packages = @(
|
||||
# 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'
|
||||
Sha256 = 'a8993608ae9263a8288e1a1d9ee2684a5632f4acc59e1e89ddd86b3b889a7367'
|
||||
Uris = @('https://www.nuget.org/api/v2/package/Microsoft.Windows.CppWinRT/3.0.260818.1')
|
||||
Pins = @()
|
||||
}
|
||||
@@ -128,11 +142,20 @@ function Assert-Pinned($Package) {
|
||||
}
|
||||
}
|
||||
|
||||
function Get-Sha256([string]$Path) { (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() }
|
||||
|
||||
# Every archive this returns, cached or downloaded, matches its pinned Sha256.
|
||||
function Get-Archive($Package) {
|
||||
$archive = Join-Path $downloads $Package.File
|
||||
if (Test-Path -LiteralPath $archive -PathType Leaf) { return $archive }
|
||||
if (Test-Path -LiteralPath $archive -PathType Leaf) {
|
||||
$actual = Get-Sha256 $archive
|
||||
if ($actual -eq $Package.Sha256) { return $archive }
|
||||
Write-Warning "$($Package.Name): cached $archive has SHA-256 $actual, expected $($Package.Sha256); discarding it and downloading again."
|
||||
Remove-Item -LiteralPath $archive -Force
|
||||
}
|
||||
$temporary = $archive + '.partial'
|
||||
$failures = @()
|
||||
$mismatch = $false
|
||||
foreach ($uri in $Package.Uris) {
|
||||
Remove-Item -LiteralPath $temporary -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "Downloading $($Package.Name) from $uri..."
|
||||
@@ -142,11 +165,21 @@ function Get-Archive($Package) {
|
||||
$failures += "$uri ($($_.Exception.Message))"
|
||||
continue
|
||||
}
|
||||
$actual = Get-Sha256 $temporary
|
||||
if ($actual -ne $Package.Sha256) {
|
||||
$failures += "$uri (SHA-256 $actual, expected $($Package.Sha256))"
|
||||
$mismatch = $true
|
||||
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 '; ')"
|
||||
$hint = ''
|
||||
if ($mismatch) {
|
||||
$hint = ' If upstream republished this archive, check the new file against an upstream-published checksum before updating its Sha256 in Prepare-Dependencies.ps1.'
|
||||
}
|
||||
throw "$($Package.Name) could not be fetched: $($failures -join '; ').$hint"
|
||||
}
|
||||
|
||||
function Expand-Package([string]$Archive, [string]$Target) {
|
||||
@@ -170,25 +203,34 @@ function Expand-Package([string]$Archive, [string]$Target) {
|
||||
if (Test-Path -LiteralPath $extract) { Remove-Item -LiteralPath $extract -Recurse -Force }
|
||||
}
|
||||
|
||||
# Records which archive a tree came from, so a pin change replaces a stale tree.
|
||||
function Get-Stamp($Package) { "$($Package.File) $($Package.Sha256)" }
|
||||
|
||||
function Test-Stamp([string]$Target, [string]$Text) {
|
||||
$stamp = $Target + '.source'
|
||||
(Test-Path -LiteralPath $stamp -PathType Leaf) -and ([IO.File]::ReadAllText($stamp) -eq $Text)
|
||||
}
|
||||
|
||||
function Install-Package($Package, [string]$Target, [string]$RequiredFile) {
|
||||
$ready = if ($RequiredFile) { Test-Path -LiteralPath $RequiredFile -PathType Leaf } else { Test-Path -LiteralPath $Target -PathType Container }
|
||||
if ($ready -and (Test-Stamp $Target (Get-Stamp $Package))) { return }
|
||||
Expand-Package (Get-Archive $Package) $Target
|
||||
[IO.File]::WriteAllText($Target + '.source', (Get-Stamp $Package))
|
||||
Write-Host "Prepared $($Package.Name)"
|
||||
}
|
||||
|
||||
foreach ($package in $packages) {
|
||||
Assert-Pinned $package
|
||||
$target = Join-Path $Destination $package.Name
|
||||
# Records which archive a tree came from, so a pin change replaces a stale tree.
|
||||
$stamp = $target + '.source'
|
||||
$current = (Test-Path -LiteralPath $stamp -PathType Leaf) -and ([IO.File]::ReadAllText($stamp) -eq $package.File)
|
||||
if ($current -and (Test-Path -LiteralPath $target -PathType Container)) { continue }
|
||||
Expand-Package (Get-Archive $package) $target
|
||||
[IO.File]::WriteAllText($stamp, $package.File)
|
||||
Write-Host "Prepared $($package.Name)"
|
||||
Install-Package $package (Join-Path $Destination $package.Name)
|
||||
}
|
||||
|
||||
$cppWinRt = Join-Path $Destination 'cppwinrt'
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $cppWinRt 'winrt\base.h') -PathType Leaf)) {
|
||||
$cppWinRtCurrent = (Test-Path -LiteralPath (Join-Path $cppWinRt 'winrt\base.h') -PathType Leaf) -and
|
||||
(Test-Stamp $cppWinRt (Get-Stamp $cppWinRtTool))
|
||||
if (-not $cppWinRtCurrent) {
|
||||
$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
|
||||
}
|
||||
Install-Package $cppWinRtTool $toolRoot $compiler
|
||||
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
|
||||
@@ -199,6 +241,7 @@ if (-not (Test-Path -LiteralPath (Join-Path $cppWinRt 'winrt\base.h') -PathType
|
||||
throw "cppwinrt.exe produced no winrt\base.h under $cppWinRt"
|
||||
}
|
||||
Copy-Item -LiteralPath (Join-Path $toolRoot 'LICENSE') -Destination (Join-Path $cppWinRt 'LICENSE.txt')
|
||||
[IO.File]::WriteAllText($cppWinRt + '.source', (Get-Stamp $cppWinRtTool))
|
||||
Write-Host 'Prepared cppwinrt'
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ param(
|
||||
[string]$PortableToolsDirectory = 'Launcher/artifacts/portable-tools',
|
||||
[string]$DependencySourceDirectory = 'Launcher/artifacts/dependencies',
|
||||
[string]$StageDirectory = 'build/recomp-test',
|
||||
[ValidateRange(1, 64)] [int]$Parallel = 3
|
||||
[ValidateRange(1, 64)] [int]$Parallel = 3,
|
||||
[ValidateSet('v2', 'v3')] [string]$X86CpuProfile = 'v3'
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
@@ -136,7 +137,7 @@ try {
|
||||
-Ninja $ninja -CCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-clang.exe') `
|
||||
-CxxCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-clang++.exe') `
|
||||
-ResourceCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-windres.exe') `
|
||||
-DependenciesDirectory $dependencies -AdditionalArguments @('-DMKW_BUILD_PRODUCTS=ON')
|
||||
-DependenciesDirectory $dependencies -AdditionalArguments @('-DMKW_BUILD_PRODUCTS=ON', "-DMKW_X86_CPU_PROFILE=$X86CpuProfile")
|
||||
Invoke-Checked $cmake $configure 'Configuring the production Windows runtime' `
|
||||
-WaitForProcessTree $false
|
||||
Invoke-Checked $cmake @('--build', $nativeBuild, '--target', 'WiiCompiled', '--parallel', "$Parallel") `
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace WiiCompiled.Setup.Common;
|
||||
|
||||
public enum X86CpuProfile
|
||||
{
|
||||
V2,
|
||||
V3
|
||||
}
|
||||
|
||||
// Setup-time copy of runtime/src/host_cpu_baseline.cpp, checked before anything is built.
|
||||
public static class HostCpuRequirement
|
||||
{
|
||||
private readonly record struct Feature(string Name, uint Leaf, int Register, int Bit, X86CpuProfile Profile);
|
||||
|
||||
// Same table and order as the runtime: register 0..3 = eax, ebx, ecx, edx.
|
||||
private static readonly Feature[] Features =
|
||||
[
|
||||
new("SSE3", 1, 2, 0, X86CpuProfile.V2),
|
||||
new("SSSE3", 1, 2, 9, X86CpuProfile.V2),
|
||||
new("CMPXCHG16B", 1, 2, 13, X86CpuProfile.V2),
|
||||
new("SSE4.1", 1, 2, 19, X86CpuProfile.V2),
|
||||
new("SSE4.2", 1, 2, 20, X86CpuProfile.V2),
|
||||
new("POPCNT", 1, 2, 23, X86CpuProfile.V2),
|
||||
new("LAHF-SAHF", 0x80000001u, 2, 0, X86CpuProfile.V2),
|
||||
new("FMA", 1, 2, 12, X86CpuProfile.V3),
|
||||
new("MOVBE", 1, 2, 22, X86CpuProfile.V3),
|
||||
new("OSXSAVE", 1, 2, 27, X86CpuProfile.V3),
|
||||
new("AVX", 1, 2, 28, X86CpuProfile.V3),
|
||||
new("F16C", 1, 2, 29, X86CpuProfile.V3),
|
||||
new("BMI1", 7, 1, 3, X86CpuProfile.V3),
|
||||
new("AVX2", 7, 1, 5, X86CpuProfile.V3),
|
||||
new("BMI2", 7, 1, 8, X86CpuProfile.V3),
|
||||
new("LZCNT", 0x80000001u, 2, 5, X86CpuProfile.V3),
|
||||
];
|
||||
|
||||
public static void EnsureSupported(X86CpuProfile profile)
|
||||
{
|
||||
if (RuntimeInformation.ProcessArchitecture != Architecture.X64)
|
||||
return;
|
||||
|
||||
// The JIT only reports AVX when the OS also saves the YMM state (XCR0), which is the
|
||||
// runtime's last check; there is no managed XGETBV.
|
||||
var missing = FindMissingFeatures(profile, CpuId, Avx.IsSupported);
|
||||
if (missing.Count > 0)
|
||||
throw new PlatformNotSupportedException(Describe(profile, missing));
|
||||
}
|
||||
|
||||
// The highest profile this machine runs; builds fall back to v2 when v3 is missing.
|
||||
public static X86CpuProfile SelectBuildProfile() =>
|
||||
RuntimeInformation.ProcessArchitecture != Architecture.X64
|
||||
? X86CpuProfile.V3
|
||||
: SelectBuildProfile(CpuId, Avx.IsSupported);
|
||||
|
||||
public static X86CpuProfile SelectBuildProfile(Func<uint, uint[]> cpuid, bool osSavesAvxState) =>
|
||||
FindMissingFeatures(X86CpuProfile.V3, cpuid, osSavesAvxState).Count == 0
|
||||
? X86CpuProfile.V3
|
||||
: X86CpuProfile.V2;
|
||||
|
||||
public static IReadOnlyList<string> FindMissingFeatures(X86CpuProfile profile,
|
||||
Func<uint, uint[]> cpuid, bool osSavesAvxState)
|
||||
{
|
||||
var maxBasic = cpuid(0)[0];
|
||||
var maxExtended = cpuid(0x80000000u)[0];
|
||||
var missing = new List<string>();
|
||||
foreach (var feature in Features)
|
||||
{
|
||||
if (feature.Profile > profile)
|
||||
continue;
|
||||
var leafAvailable = (feature.Leaf & 0x80000000u) != 0
|
||||
? feature.Leaf <= maxExtended
|
||||
: feature.Leaf <= maxBasic;
|
||||
if (!leafAvailable || (cpuid(feature.Leaf)[feature.Register] & (1u << feature.Bit)) == 0)
|
||||
missing.Add(feature.Name);
|
||||
}
|
||||
|
||||
if (missing.Count == 0 && profile >= X86CpuProfile.V3 && !osSavesAvxState)
|
||||
missing.Add("operating system support for AVX register state (XCR0 YMM bits)");
|
||||
return missing;
|
||||
}
|
||||
|
||||
public static string Describe(X86CpuProfile profile, IReadOnlyList<string> missing) =>
|
||||
profile == X86CpuProfile.V2
|
||||
? "This build needs a processor that supports the x86-64-v2 instruction set.\n\n" +
|
||||
"Missing on this machine: " + string.Join(", ", missing) + "\n\n" +
|
||||
"x86-64-v2 covers Intel Core processors from Nehalem (2008) onward and AMD processors " +
|
||||
"from Jaguar (2013) onward."
|
||||
: "This build needs a processor that supports the x86-64-v3 instruction set.\n\n" +
|
||||
"Missing on this machine: " + string.Join(", ", missing) + "\n\n" +
|
||||
"x86-64-v3 covers Intel Core processors from Haswell (4th generation, 2013) onward " +
|
||||
"and AMD processors from Excavator (2015) onward.";
|
||||
|
||||
private static uint[] CpuId(uint leaf)
|
||||
{
|
||||
var (eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)leaf), 0);
|
||||
return [unchecked((uint)eax), unchecked((uint)ebx), unchecked((uint)ecx), unchecked((uint)edx)];
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,8 @@ internal static class Program
|
||||
|
||||
private static async Task InstallAsync(Dictionary<string, string?> flags, IInstallReporter reporter, CancellationToken token)
|
||||
{
|
||||
// local-build.sh falls back to an x86-64-v2 build when this CPU lacks v3.
|
||||
HostCpuRequirement.EnsureSupported(X86CpuProfile.V2);
|
||||
var retroDir = flags.GetValueOrDefault("retro-dir");
|
||||
var installsRetro = !string.IsNullOrEmpty(retroDir);
|
||||
var downloadPayload = flags.ContainsKey("download-retro-wfc-payload");
|
||||
|
||||
@@ -60,7 +60,8 @@ internal sealed class LocalBuildService
|
||||
BuildProfile.RetroRewind => "retro-rewind",
|
||||
_ => "both"
|
||||
},
|
||||
"-OutputDirectory", outputDirectory
|
||||
"-OutputDirectory", outputDirectory,
|
||||
"-X86CpuProfile", HostCpuRequirement.SelectBuildProfile() == X86CpuProfile.V2 ? "v2" : "v3"
|
||||
};
|
||||
if (baseOutputDirectory is not null)
|
||||
{
|
||||
|
||||
@@ -64,6 +64,8 @@ internal static class Program
|
||||
|
||||
if (command.Mode is AppMode.SilentInstall or AppMode.RepairProducts)
|
||||
{
|
||||
// CPUs without x86-64-v3 get an x86-64-v2 build.
|
||||
HostCpuRequirement.EnsureSupported(X86CpuProfile.V2);
|
||||
using var cancellationSignal = CancellationSignal.ObserveEnvironment();
|
||||
return command.Mode == AppMode.SilentInstall
|
||||
? ConsoleCommands.Install(command, cancellationSignal.Token).GetAwaiter().GetResult()
|
||||
|
||||
@@ -36,6 +36,7 @@ internal static class SelfTests
|
||||
Test("Toolkit accompanies the workspace", TestToolkitRefreshDecision, failures);
|
||||
Test("Retro-WFC payload snapshot reconciliation", TestRetroWfcPayloadSnapshotReconciliation, failures);
|
||||
Test("Retro-WFC transient retry policy", TestRetroWfcTransientRetryPolicy, failures);
|
||||
Test("Host CPU requirement", TestHostCpuRequirement, failures);
|
||||
Test("Shared runtime configuration", () => TestPathSettingRoundTrip("dvd_root",
|
||||
RuntimeConfiguration.SetDvdRoot, RuntimeConfiguration.RemoveDvdRootIfOwned), failures);
|
||||
Test("Canonical Retro Rewind configuration", () => TestPathSettingRoundTrip("retro_rewind_root",
|
||||
@@ -994,6 +995,57 @@ internal static class SelfTests
|
||||
throw new Exception("A non-I/O failure would be retried.");
|
||||
}
|
||||
|
||||
private static void TestHostCpuRequirement()
|
||||
{
|
||||
// Leaf 1 ecx, leaf 7 ebx, leaf 0x80000001 ecx of a v2-only and a v3 processor.
|
||||
const uint v2Leaf1 = (1u << 0) | (1u << 9) | (1u << 13) | (1u << 19) | (1u << 20) | (1u << 23);
|
||||
const uint v3Leaf1 = v2Leaf1 | (1u << 12) | (1u << 22) | (1u << 27) | (1u << 28) | (1u << 29);
|
||||
const uint v3Leaf7 = (1u << 3) | (1u << 5) | (1u << 8);
|
||||
Func<uint, uint[]> Cpu(uint maxBasic, uint leaf1, uint leaf7, uint extended) => leaf => leaf switch
|
||||
{
|
||||
0 => [maxBasic, 0, 0, 0],
|
||||
1 => [0, 0, leaf1, 0],
|
||||
7 => [0, leaf7, 0, 0],
|
||||
0x80000000u => [0x80000001u, 0, 0, 0],
|
||||
0x80000001u => [0, 0, extended, 0],
|
||||
_ => [0, 0, 0, 0]
|
||||
};
|
||||
var nehalem = Cpu(11, v2Leaf1, 0, 1u);
|
||||
var haswell = Cpu(13, v3Leaf1, v3Leaf7, 1u | (1u << 5));
|
||||
|
||||
void Expect(IReadOnlyList<string> actual, string expected, string what)
|
||||
{
|
||||
if (string.Join(", ", actual) != expected)
|
||||
throw new Exception($"{what}: expected [{expected}], got [{string.Join(", ", actual)}].");
|
||||
}
|
||||
|
||||
Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V2, nehalem, false), "",
|
||||
"A v2 processor was rejected for the v2 build");
|
||||
Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V3, nehalem, false),
|
||||
"FMA, MOVBE, OSXSAVE, AVX, F16C, BMI1, AVX2, BMI2, LZCNT", "A v2 processor for the v3 build");
|
||||
Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V3, haswell, true), "",
|
||||
"A v3 processor was rejected");
|
||||
Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V2, haswell, false), "",
|
||||
"A v3 processor was rejected for the v2 build");
|
||||
Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V3, haswell, false),
|
||||
"operating system support for AVX register state (XCR0 YMM bits)", "Disabled AVX state");
|
||||
Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V3, Cpu(6, v3Leaf1, v3Leaf7, 1u | (1u << 5)), true),
|
||||
"BMI1, AVX2, BMI2", "Unavailable leaf 7");
|
||||
Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V2, Cpu(11, v2Leaf1, 0, 0), false),
|
||||
"LAHF-SAHF", "Missing LAHF/SAHF");
|
||||
|
||||
if (HostCpuRequirement.SelectBuildProfile(nehalem, false) != X86CpuProfile.V2)
|
||||
throw new Exception("A v2 processor was not given the v2 build.");
|
||||
if (HostCpuRequirement.SelectBuildProfile(haswell, true) != X86CpuProfile.V3)
|
||||
throw new Exception("A v3 processor was not given the v3 build.");
|
||||
if (HostCpuRequirement.SelectBuildProfile(haswell, false) != X86CpuProfile.V2)
|
||||
throw new Exception("A v3 processor without AVX state was given the v3 build.");
|
||||
|
||||
var message = HostCpuRequirement.Describe(X86CpuProfile.V3, ["AVX2"]);
|
||||
if (!message.Contains("x86-64-v3") || !message.Contains("Missing on this machine: AVX2"))
|
||||
throw new Exception("The unsupported-processor message lost its detail.");
|
||||
}
|
||||
|
||||
private static void TestRetroWfcTransientRetryPolicy()
|
||||
{
|
||||
if (!InputValidation.IsTransientRetroWfcDownloadFailure(
|
||||
|
||||
@@ -86,6 +86,17 @@ assets="$workspace/Assets"; generated="$workspace/generated"
|
||||
functions="$generated/functions"; metadata="$generated/base_translation_output.json"; manifest_dir="$workspace/build/base"
|
||||
manifest="$manifest_dir/mkwii_base_manifest.json"; shards="$generated/build_shards"
|
||||
native_build="$workspace/native-build-macos-$macos_arch"
|
||||
x86_cpu_profile=v3
|
||||
if [[ "$macos_arch" == x86_64 ]]; then
|
||||
native_macros=$(clang -march=native -dM -E -x c /dev/null 2>/dev/null || true)
|
||||
for macro in __AVX__ __AVX2__ __BMI__ __BMI2__ __F16C__ __FMA__ __LZCNT__ __MOVBE__; do
|
||||
if ! grep -q "^#define $macro " <<<"$native_macros"; then
|
||||
x86_cpu_profile=v2
|
||||
printf 'MKWCBUILD: This CPU does not support x86-64-v3; building for x86-64-v2\n'
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [[ -n "$game" ]]; then "$script_dir/macos/extract-disc.command" --workspace "$workspace" --game "$game" --assets-dir "$assets" --nodtool "$nodtool"; fi
|
||||
assert_file "$assets/main.dol" 'extracted main.dol'; assert_file "$assets/StaticR.rel" 'extracted StaticR.rel'
|
||||
# The translation project is the one pinned to the extracted main.dol, which decides the region.
|
||||
@@ -172,7 +183,7 @@ fi
|
||||
step configure-native 'Configuring the native toolchain'
|
||||
# Use Aurora's pinned SDL3 source on macOS. A system SDL3 can be older than
|
||||
# Aurora's required API even when find_package() succeeds.
|
||||
"$cmake_bin" -S "$workspace/runtime" -B "$native_build" -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_MAKE_PROGRAM="$ninja_bin" -DCMAKE_OSX_ARCHITECTURES="$macos_arch" -DCMAKE_OSX_DEPLOYMENT_TARGET="$macos_deployment_target" -DMKW_TRANSLATED_COMPILE_JOBS="$translated_jobs" -DAURORA_SDL3_PROVIDER=vendor -DMKW_SETUP_VERSION="$setup_version"
|
||||
"$cmake_bin" -S "$workspace/runtime" -B "$native_build" -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_MAKE_PROGRAM="$ninja_bin" -DCMAKE_OSX_ARCHITECTURES="$macos_arch" -DCMAKE_OSX_DEPLOYMENT_TARGET="$macos_deployment_target" -DMKW_TRANSLATED_COMPILE_JOBS="$translated_jobs" -DMKW_X86_CPU_PROFILE="$x86_cpu_profile" -DAURORA_SDL3_PROVIDER=vendor -DMKW_SETUP_VERSION="$setup_version"
|
||||
mkw_write_identity "$toolchain_provenance" ToolchainFingerprint "$toolchain_fingerprint"
|
||||
targets=(); [[ "$profile" != retro-rewind ]] && targets+=(WiiCompiled); [[ "$profile" != base ]] && targets+=(RetroRewind)
|
||||
step compile "Compiling ${targets[*]} locally"; "$cmake_bin" --build "$native_build" --target "${targets[@]}" --parallel "$global_jobs"
|
||||
|
||||
@@ -41,6 +41,28 @@ done
|
||||
|
||||
host_arch=$(uname -m)
|
||||
case "$host_arch" in arm64|x86_64) ;; *) fail "unsupported macOS architecture: $host_arch" ;; esac
|
||||
# Same x86-64-v2 check as runtime/src/host_cpu_baseline.cpp, before anything is built;
|
||||
# local-build-macos.command builds for v2 when the CPU lacks v3.
|
||||
if [[ "$host_arch" == x86_64 ]]; then
|
||||
cpu_features=$(/usr/sbin/sysctl -n machdep.cpu.features machdep.cpu.extfeatures 2>/dev/null | tr '\n' ' ' || true)
|
||||
if [[ -n "${cpu_features// /}" ]]; then
|
||||
missing_features=""
|
||||
for feature in SSE3=SSE3 SSSE3=SSSE3 CX16=CMPXCHG16B SSE4.1=SSE4.1 SSE4.2=SSE4.2 POPCNT=POPCNT \
|
||||
LAHF=LAHF-SAHF; do
|
||||
[[ " $cpu_features " == *" ${feature%%=*} "* ]] || missing_features+="${missing_features:+, }${feature#*=}"
|
||||
done
|
||||
if [[ -n "$missing_features" ]]; then
|
||||
message="This build needs a processor that supports the x86-64-v2 instruction set.
|
||||
|
||||
Missing on this machine: $missing_features
|
||||
|
||||
x86-64-v2 covers Intel Core processors from Nehalem (2008) onward and AMD processors from Jaguar (2013) onward."
|
||||
printf 'WiiCompiled Setup: %s\n' "$message" >&2
|
||||
notice "$message"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
host_tools="$resources/tools/$host_arch"
|
||||
nodtool="$host_tools/nodtool"
|
||||
translator="$host_tools/Translator.Cli"
|
||||
|
||||
+1
-1
Submodule aurora-main updated: ff0b617a92...23385378e0
@@ -7,6 +7,7 @@
|
||||
#include "memory.h"
|
||||
#include "runtime_product.h"
|
||||
|
||||
#include <SDL3/SDL_clipboard.h>
|
||||
#include <SDL3/SDL_events.h>
|
||||
|
||||
#include <atomic>
|
||||
@@ -27,11 +28,32 @@ constexpr uint32_t kPageStateActive = 4;
|
||||
constexpr uint32_t kVtableGetTypeInfoOffset = 0x60;
|
||||
constexpr int kBackspace = -1;
|
||||
constexpr size_t kMaxPendingKeys = 32;
|
||||
constexpr size_t kFriendCodeDigits = 12;
|
||||
|
||||
std::mutex g_pendingMutex;
|
||||
std::vector<int> g_pending;
|
||||
std::atomic_bool g_pageFocused{false};
|
||||
|
||||
bool IsPaste(const SDL_KeyboardEvent& key) {
|
||||
return !key.repeat && key.key == SDLK_V && (key.mod & (SDL_KMOD_CTRL | SDL_KMOD_GUI)) != 0 &&
|
||||
(key.mod & SDL_KMOD_ALT) == 0;
|
||||
}
|
||||
|
||||
void AppendClipboardDigits(std::vector<int>& keys) {
|
||||
char* text = SDL_GetClipboardText();
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
size_t digits = 0;
|
||||
for (const char* c = text; *c && digits < kFriendCodeDigits; ++c) {
|
||||
if (*c >= '0' && *c <= '9') {
|
||||
keys.push_back(*c - '0');
|
||||
++digits;
|
||||
}
|
||||
}
|
||||
SDL_free(text);
|
||||
}
|
||||
|
||||
std::optional<int> KeyValue(const SDL_KeyboardEvent& key) {
|
||||
if ((key.mod & (SDL_KMOD_CTRL | SDL_KMOD_ALT | SDL_KMOD_GUI)) != 0) {
|
||||
return std::nullopt;
|
||||
@@ -98,16 +120,27 @@ void HandleEvents(const AuroraEvent* events) noexcept {
|
||||
if (!events || !g_pageFocused.load(std::memory_order_acquire) || InputBindings::InputBlocked()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock(g_pendingMutex);
|
||||
std::vector<int> keys;
|
||||
for (const AuroraEvent* ev = events; ev->type != AURORA_NONE; ++ev) {
|
||||
if (ev->type != AURORA_SDL_EVENT || ev->sdl.type != SDL_EVENT_KEY_DOWN) {
|
||||
continue;
|
||||
}
|
||||
const std::optional<int> key = KeyValue(ev->sdl.key);
|
||||
if (key && g_pending.size() < kMaxPendingKeys) {
|
||||
g_pending.push_back(*key);
|
||||
if (IsPaste(ev->sdl.key)) {
|
||||
AppendClipboardDigits(keys);
|
||||
} else if (const std::optional<int> key = KeyValue(ev->sdl.key)) {
|
||||
keys.push_back(*key);
|
||||
}
|
||||
}
|
||||
if (keys.empty()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock(g_pendingMutex);
|
||||
for (const int key : keys) {
|
||||
if (g_pending.size() >= kMaxPendingKeys) {
|
||||
break;
|
||||
}
|
||||
g_pending.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FriendCodeKeyboard
|
||||
|
||||
Reference in New Issue
Block a user