mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-10-25 07:16:12 -04:00
Fix prebuilt aurora package being rejected (#357)
* fix prebuilt package rejected on user machines * Time out a hung translator step The translator can hang after a crash instead of exiting, and the installer's clean retry runs only on a failed exit. Each translator step now gets 1800 s; past that its process tree is killed and the step fails, so the retry runs. * time out mod awareness check too --------- Co-authored-by: therenow9 <60898774+therenow9@users.noreply.github.com>
This commit is contained in:
@@ -278,6 +278,24 @@ $packagedRuntimeFingerprint = (Get-Content -LiteralPath (Join-Path $workspace 'D
|
||||
if ($stagedRuntimeFingerprint -ne $packagedRuntimeFingerprint) {
|
||||
throw "The staged runtime ($stagedRuntimeFingerprint) does not match the precompiled runtime archive ($packagedRuntimeFingerprint)."
|
||||
}
|
||||
# Users' builds run LocalBuild.ps1 under Windows PowerShell 5.1, whatever shell built this
|
||||
# installer, so the staged package is accepted (or not) exactly the way theirs will be.
|
||||
$prebuiltGate = Join-Path $workRoot 'native-prebuilt-gate.ps1'
|
||||
@'
|
||||
param([string]$Workspace, [string]$Toolkit)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Set-StrictMode -Version 3.0
|
||||
. (Join-Path $Workspace 'NativeBuildFlags.ps1')
|
||||
$package = Resolve-MkwNativePrebuiltDirectory (Join-Path $Workspace 'Dependencies') `
|
||||
(Join-Path $Toolkit 'llvm-mingw\bin') (Join-Path $Workspace 'aurora-main') (Join-Path $Workspace 'runtime\third_party')
|
||||
if (-not $package) { exit 3 }
|
||||
'@ | Set-Content -LiteralPath $prebuiltGate -Encoding UTF8
|
||||
& (Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe') -NoLogo -NoProfile -NonInteractive `
|
||||
-ExecutionPolicy Bypass -File $prebuiltGate -Workspace $workspace -Toolkit $toolkit
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Windows PowerShell rejects the staged precompiled aurora package (exit $LASTEXITCODE); every installation would build aurora from source."
|
||||
}
|
||||
Remove-Item -LiteralPath $prebuiltGate -Force
|
||||
|
||||
[IO.Directory]::CreateDirectory((Join-Path $payloadRoot 'host')) | Out-Null
|
||||
Copy-Item $setupHost (Join-Path $payloadRoot 'host\WiiCompiled-Setup.exe')
|
||||
|
||||
+26
-71
@@ -34,65 +34,6 @@ Set-StrictMode -Version 3.0
|
||||
# See NativeBuildFlags.ps1; Build-Installer.ps1 stages it beside this script.
|
||||
. (Join-Path $PSScriptRoot 'NativeBuildFlags.ps1')
|
||||
|
||||
function Resolve-NativePrebuiltDirectory([string]$DependenciesDirectory, [string]$ToolchainBin, [string]$AuroraDirectory, [string]$ThirdPartyDirectory) {
|
||||
<#
|
||||
The shipped precompiled aurora/third-party package, verified against its recorded provenance
|
||||
(exact compiler, exact flags) before use. Anything unexpected falls back to building from source.
|
||||
#>
|
||||
$package = Join-Path $DependenciesDirectory 'native_prebuilt'
|
||||
$provenancePath = Join-Path $package 'provenance.json'
|
||||
if (-not (Test-Path -LiteralPath $provenancePath -PathType Leaf)) {
|
||||
Write-Host 'MKWCBUILD: No precompiled aurora package was shipped; building it from source'
|
||||
return ''
|
||||
}
|
||||
try {
|
||||
$provenance = Get-Content -LiteralPath $provenancePath -Raw | ConvertFrom-Json
|
||||
$compiler = Join-Path $ToolchainBin 'clang-22.exe'
|
||||
$compilerHash = Get-MkwFileSha256 $compiler
|
||||
if ($provenance.CompilerSha256 -ne $compilerHash) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built by a different compiler; building it from source'
|
||||
return ''
|
||||
}
|
||||
if ($provenance.FlagFingerprint -ne (Get-MkwNativeFlagFingerprint)) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built with different flags; building it from source'
|
||||
return ''
|
||||
}
|
||||
# The archives embed Dawn's headers and link its import library, so a
|
||||
# dawn_prebuilt tree that is not the one they were harvested against is
|
||||
# an ABI mismatch that only shows up as a crash inside the GPU backend.
|
||||
$recordedDawn = $provenance.PSObject.Properties['DawnRuntimeSha256']
|
||||
if ($null -eq $recordedDawn -or
|
||||
$recordedDawn.Value -ne (Get-MkwDawnRuntimeSha256 $DependenciesDirectory)) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built against a different Dawn; building it from source'
|
||||
return ''
|
||||
}
|
||||
# The archives are aurora; the runtime compiled here calls its headers.
|
||||
# If this workspace's aurora sources are not the ones that were harvested
|
||||
# (a newer toolkit, or a locally modified tree), linking the package would
|
||||
# mix two versions of aurora, so build it from source instead.
|
||||
$recordedAurora = $provenance.PSObject.Properties['AuroraSourceFingerprint']
|
||||
if ($null -eq $recordedAurora -or
|
||||
$recordedAurora.Value -ne (Get-MkwAuroraSourceFingerprint $AuroraDirectory)) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built from different aurora sources; building it from source'
|
||||
return ''
|
||||
}
|
||||
# Same reasoning for the vendored Crypto++ the package also carries:
|
||||
# first-party TUs compile against this workspace's third_party headers,
|
||||
# so a package harvested from an older tree must not be linked here.
|
||||
$recordedThirdParty = $provenance.PSObject.Properties['ThirdPartySourceFingerprint']
|
||||
if ($null -eq $recordedThirdParty -or
|
||||
$recordedThirdParty.Value -ne (Get-MkwThirdPartySourceFingerprint $ThirdPartyDirectory)) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built from different vendored third-party sources; building it from source'
|
||||
return ''
|
||||
}
|
||||
} catch {
|
||||
Write-Host "MKWCBUILD: The precompiled aurora package could not be validated ($($_.Exception.Message)); building it from source"
|
||||
return ''
|
||||
}
|
||||
Write-Host 'MKWCBUILD: Using the precompiled aurora and third-party libraries'
|
||||
return $package
|
||||
}
|
||||
|
||||
function Write-MkwBuildStep([string]$StepId, [string]$Message) {
|
||||
<#
|
||||
Announces a build step. The identifier is the contract (BuildStepIds in
|
||||
@@ -160,6 +101,8 @@ if (-not [string]::IsNullOrWhiteSpace($RetroRewindPackageDirectory) -and
|
||||
$RetroRewindPackageDirectory = $Workspace + $RetroRewindPackageDirectory.Substring($realWorkspace.Length)
|
||||
}
|
||||
$translator = Join-Path $Toolkit 'Translator\Translator.Cli.exe'
|
||||
# A translator step takes 3-19 s on 16 threads; past this it has hung, and failing lets the clean retry run.
|
||||
$translatorTimeoutSeconds = 1800
|
||||
$toolchain = Get-MkwBuildSafePath $Toolkit 'toolchain' 'CMake\bin\cmake.exe'
|
||||
$cmake = Join-Path $toolchain 'CMake\bin\cmake.exe'
|
||||
$ninja = Join-Path $toolchain 'Ninja\ninja.exe'
|
||||
@@ -208,8 +151,9 @@ if ($Parallel -gt 0) {
|
||||
$globalJobs = $Parallel
|
||||
} else {
|
||||
$translatorThreads = [math]::Max(1, [math]::Min([Environment]::ProcessorCount, 16))
|
||||
# A translated TU peaks around 0.26 GB in clang; 0.5 GiB each after a 2 GiB reserve.
|
||||
$translatedJobs = [math]::Max(1, [math]::Min([Environment]::ProcessorCount,
|
||||
[math]::Floor($memoryGiB / 2)))
|
||||
[math]::Floor(($memoryGiB - 2) / 0.5)))
|
||||
$globalJobs = [math]::Max($translatedJobs, [Environment]::ProcessorCount)
|
||||
}
|
||||
|
||||
@@ -286,11 +230,18 @@ try {
|
||||
# same translated functions produces the same base tree. Only the translator can
|
||||
# decide that - it takes parsing the Kamek patch set against the recorded translated
|
||||
# function ranges - and it fails closed, so anything but exit 0 retranslates.
|
||||
& $translator @(
|
||||
'check-base-mod-awareness', '--project', $project, '--profile', 'retro-rewind',
|
||||
'--translation-output-metadata', $baseMetadata, '--code-pul', $retroCodePul
|
||||
) | Write-Host
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
$modAware = $true
|
||||
try {
|
||||
Invoke-Checked $translator @(
|
||||
'check-base-mod-awareness', '--project', $project, '--profile', 'retro-rewind',
|
||||
'--translation-output-metadata', $baseMetadata, '--code-pul', $retroCodePul
|
||||
) 'Checking whether the base translation covers the new Code.pul' `
|
||||
-TimeoutSeconds $translatorTimeoutSeconds
|
||||
} catch {
|
||||
Write-Host "MKWCBUILD: $($_.Exception.Message)"
|
||||
$modAware = $false
|
||||
}
|
||||
if (-not $modAware) {
|
||||
Write-MkwBuildStep 'retranslate-base' 'The base translation is stale; retranslating the base game for the new Code.pul'
|
||||
$reuseBase = $false
|
||||
}
|
||||
@@ -313,12 +264,14 @@ try {
|
||||
'--outdir', $functions, '--output-metadata', $baseMetadata,
|
||||
'--production-source-bundle', (Join-Path $generated 'base_translation_sources.bin'),
|
||||
'--no-function-files', '--prune-stale', '--threads', $translatorThreads
|
||||
) 'Translating the user-owned base game' -StepId 'translate-base'
|
||||
) 'Translating the user-owned base game' -StepId 'translate-base' `
|
||||
-TimeoutSeconds $translatorTimeoutSeconds
|
||||
|
||||
Invoke-Checked $translator @(
|
||||
'emit-base-manifest', '--project', $project, '--out', $baseManifestDir,
|
||||
'--functions-dir', $functions, '--translation-output-metadata', $baseMetadata, '--region', $pins.Region
|
||||
) 'Creating the local base translation manifest' -StepId 'emit-base-manifest'
|
||||
) 'Creating the local base translation manifest' -StepId 'emit-base-manifest' `
|
||||
-TimeoutSeconds $translatorTimeoutSeconds
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($TranslationFingerprint)) {
|
||||
[ordered]@{ SchemaVersion = 1; TranslationFingerprint = $TranslationFingerprint; DolSha256 = $pins.DolSha256 } |
|
||||
@@ -348,11 +301,12 @@ try {
|
||||
throw 'Retro Rewind requires either -RetroWfcOfflineDirectory or -SkipRetroWfcPayload.'
|
||||
}
|
||||
Invoke-Checked $translator $translateModArguments 'Translating the selected Retro Rewind Code.pul' `
|
||||
-StepId 'translate-mod'
|
||||
-StepId 'translate-mod' -TimeoutSeconds $translatorTimeoutSeconds
|
||||
}
|
||||
|
||||
Invoke-Checked $translator @('generate-data-init', '--project', $project) `
|
||||
'Generating local game data initialization' -StepId 'generate-data-init'
|
||||
'Generating local game data initialization' -StepId 'generate-data-init' `
|
||||
-TimeoutSeconds $translatorTimeoutSeconds
|
||||
|
||||
$shardArgs = @(
|
||||
'emit-build-shards', '--project', $project, '--base-metadata', $baseMetadata,
|
||||
@@ -364,7 +318,8 @@ try {
|
||||
$shardArgs += @('--resolved-profile', (Join-Path $retroOut 'resolved_dispatch_profile.json'),
|
||||
'--retro-cpp-dir', (Join-Path $retroOut 'cpp'))
|
||||
}
|
||||
Invoke-Checked $translator $shardArgs 'Preparing local native build shards' -StepId 'emit-build-shards'
|
||||
Invoke-Checked $translator $shardArgs 'Preparing local native build shards' -StepId 'emit-build-shards' `
|
||||
-TimeoutSeconds $translatorTimeoutSeconds
|
||||
|
||||
# The build directory is kept whenever the exact toolchain that filled it is the one
|
||||
# installed now and its CMake cache still belongs to this workspace path. Object files are
|
||||
@@ -396,7 +351,7 @@ try {
|
||||
}
|
||||
}
|
||||
$dependencies = Join-Path $Workspace 'Dependencies'
|
||||
$nativePrebuilt = Resolve-NativePrebuiltDirectory $dependencies $toolchainBin `
|
||||
$nativePrebuilt = Resolve-MkwNativePrebuiltDirectory $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'
|
||||
|
||||
+118
-54
@@ -157,7 +157,8 @@ function Resolve-MkwProjectForAssets([string]$Workspace, [string]$AssetsDirector
|
||||
}
|
||||
|
||||
function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Description,
|
||||
[string]$LogPrefix = 'MKWCBUILD', [string]$StepId = '', [bool]$WaitForProcessTree = $true) {
|
||||
[string]$LogPrefix = 'MKWCBUILD', [string]$StepId = '', [bool]$WaitForProcessTree = $true,
|
||||
[int]$TimeoutSeconds = 0) {
|
||||
<#
|
||||
Runs a build tool and turns a non-zero exit code into a described failure. By default,
|
||||
Start-Process -Wait waits for the whole process tree, since a .NET single-file bundle host may
|
||||
@@ -166,6 +167,7 @@ function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Descri
|
||||
Start-Process doesn't publish $LASTEXITCODE, so this sets it manually for callers that check it.
|
||||
-StepId emits the machine-readable form the installer's progress bar consumes (BuildStepIds in
|
||||
WiiCompiled.Setup/InstallProgress.cs); the human sentence stays on the same log line.
|
||||
-TimeoutSeconds waits on the process itself and kills its tree when time runs out.
|
||||
#>
|
||||
if ($StepId) { Write-Host "${LogPrefix}:STEP:${StepId} $Description" }
|
||||
else { Write-Host "${LogPrefix}: $Description" }
|
||||
@@ -174,7 +176,17 @@ function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Descri
|
||||
# Backslashes directly before the closing quote would otherwise escape it.
|
||||
'"' + ($_ -replace '(\\+)$', '$1$1') + '"'
|
||||
})
|
||||
if ($WaitForProcessTree) {
|
||||
if ($TimeoutSeconds -gt 0) {
|
||||
$process = Start-Process -FilePath $FilePath -ArgumentList $quotedArguments -NoNewWindow -PassThru
|
||||
# Holding the handle keeps ExitCode readable once the process has exited.
|
||||
$null = $process.Handle
|
||||
if (-not $process.WaitForExit($TimeoutSeconds * 1000)) {
|
||||
# taskkill's stderr would end the script under 'Stop' before the message below.
|
||||
try { & taskkill.exe /T /F /PID $process.Id 2>&1 | Out-Null } catch {}
|
||||
throw "$Description did not finish within $TimeoutSeconds seconds and was stopped."
|
||||
}
|
||||
$exitCode = $process.ExitCode
|
||||
} elseif ($WaitForProcessTree) {
|
||||
$process = Start-Process -FilePath $FilePath -ArgumentList $quotedArguments `
|
||||
-NoNewWindow -Wait -PassThru
|
||||
$exitCode = $process.ExitCode
|
||||
@@ -236,69 +248,121 @@ function Get-MkwDawnRuntimeSha256([string]$DependenciesDirectory) {
|
||||
return Get-MkwFileSha256 $runtime
|
||||
}
|
||||
|
||||
function Get-MkwThirdPartySourceFingerprint([string]$ThirdPartyDirectory) {
|
||||
function ConvertTo-MkwHex([byte[]]$Bytes) {
|
||||
return [BitConverter]::ToString($Bytes).Replace('-', '').ToLowerInvariant()
|
||||
}
|
||||
|
||||
function Get-MkwSourceTreeFingerprint([string]$Directory, [string[]]$ExcludedTopDirectories = @()) {
|
||||
<#
|
||||
SHA-256 over runtime/third_party, the vendored sources behind the prebuilt package. The
|
||||
precompiled Crypto++ archive is linked while first-party TUs compile against the same headers,
|
||||
so a workspace whose vendored tree moved on must not consume archives harvested from an older
|
||||
one (same reasoning as the aurora fingerprint below), skipping dot-paths by name the same way.
|
||||
Returns '' when absent.
|
||||
SHA-256 over "relative-path content-sha256" lines of a source tree. It must come out the same
|
||||
under powershell.exe 5.1 and pwsh 7 and for any checkout's line endings, because the package is
|
||||
harvested on a release machine and re-checked on every user's: paths are sorted ordinally (not
|
||||
with Sort-Object, whose culture collation differs between NLS and ICU) and text content is hashed
|
||||
with CRLF folded to LF. Dot-paths are skipped by name, not by the hidden attribute, which the
|
||||
payload zip drops. Returns '' when the tree is absent.
|
||||
#>
|
||||
if ([string]::IsNullOrWhiteSpace($ThirdPartyDirectory)) { return '' }
|
||||
if (-not (Test-Path -LiteralPath $ThirdPartyDirectory -PathType Container)) { return '' }
|
||||
$root = [IO.Path]::GetFullPath($ThirdPartyDirectory).TrimEnd('\')
|
||||
$files = Get-ChildItem -LiteralPath $root -Recurse -File -Force |
|
||||
Where-Object { -not ($_.FullName.Substring($root.Length + 1) -split '\\' | Where-Object { $_.StartsWith('.') }) } |
|
||||
Sort-Object { $_.FullName.Substring($root.Length + 1).Replace('\', '/') }
|
||||
if ([string]::IsNullOrWhiteSpace($Directory)) { return '' }
|
||||
if (-not (Test-Path -LiteralPath $Directory -PathType Container)) { return '' }
|
||||
$root = [IO.Path]::GetFullPath($Directory).TrimEnd('\')
|
||||
$relatives = [Collections.Generic.List[string]]::new()
|
||||
foreach ($file in [IO.Directory]::EnumerateFiles($root, '*', [IO.SearchOption]::AllDirectories)) {
|
||||
$relative = $file.Substring($root.Length + 1).Replace('\', '/')
|
||||
$parts = $relative.Split('/')
|
||||
if ($parts.Length -gt 1 -and $ExcludedTopDirectories -contains $parts[0]) { continue }
|
||||
$hidden = $false
|
||||
foreach ($part in $parts) { if ($part.StartsWith('.', [StringComparison]::Ordinal)) { $hidden = $true; break } }
|
||||
if (-not $hidden) { $relatives.Add($relative) }
|
||||
}
|
||||
$sorted = $relatives.ToArray()
|
||||
[Array]::Sort($sorted, [StringComparer]::Ordinal)
|
||||
|
||||
$latin1 = [Text.Encoding]::GetEncoding(28591)
|
||||
$sha = [Security.Cryptography.SHA256]::Create()
|
||||
try {
|
||||
$builder = [Text.StringBuilder]::new()
|
||||
foreach ($file in $files) {
|
||||
$relative = $file.FullName.Substring($root.Length + 1).Replace('\', '/')
|
||||
$content = Get-MkwFileSha256 $file.FullName
|
||||
[void]$builder.Append($relative).Append(' ').Append($content).Append("`n")
|
||||
foreach ($relative in $sorted) {
|
||||
$bytes = [IO.File]::ReadAllBytes($root + '\' + $relative.Replace('/', '\'))
|
||||
# Latin-1 maps bytes 1:1, so the round trip only changes the line endings.
|
||||
$text = $latin1.GetString($bytes)
|
||||
if ($text.IndexOf([char]0) -lt 0 -and $text.Contains("`r`n")) {
|
||||
$bytes = $latin1.GetBytes($text.Replace("`r`n", "`n"))
|
||||
}
|
||||
[void]$builder.Append($relative).Append(' ').Append((ConvertTo-MkwHex $sha.ComputeHash($bytes))).Append("`n")
|
||||
}
|
||||
$bytes = $sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($builder.ToString()))
|
||||
return ConvertTo-MkwHex $sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($builder.ToString()))
|
||||
} finally { $sha.Dispose() }
|
||||
return (($bytes | ForEach-Object { $_.ToString('x2') }) -join '')
|
||||
}
|
||||
|
||||
function Get-MkwThirdPartySourceFingerprint([string]$ThirdPartyDirectory) {
|
||||
<#
|
||||
runtime/third_party, the vendored sources behind the prebuilt package. The precompiled Crypto++
|
||||
archive is linked while first-party TUs compile against the same headers, so a workspace whose
|
||||
vendored tree moved on must not consume archives harvested from an older one.
|
||||
#>
|
||||
return Get-MkwSourceTreeFingerprint $ThirdPartyDirectory
|
||||
}
|
||||
|
||||
function Get-MkwAuroraSourceFingerprint([string]$AuroraDirectory) {
|
||||
<#
|
||||
SHA-256 over the aurora sources the precompiled archives were harvested from. The compiler,
|
||||
flag, and Dawn digests only prove the package agrees with its target environment; none notice
|
||||
aurora itself moving on, and since the runtime calls aurora headers directly, a package
|
||||
harvested before an aurora change links old code against new call sites (undefined symbol at
|
||||
best, silently stale renderer at worst). extern/ is excluded because the payload ships those
|
||||
trees separately. Returns '' when the tree is absent.
|
||||
The aurora sources the precompiled archives were harvested from. The compiler, flag, and Dawn
|
||||
digests only prove the package agrees with its target environment; none notice aurora itself
|
||||
moving on, and since the runtime calls aurora headers directly, a package harvested before an
|
||||
aurora change links old code against new call sites. extern/ is excluded because the payload
|
||||
ships those trees separately.
|
||||
#>
|
||||
if ([string]::IsNullOrWhiteSpace($AuroraDirectory)) { return '' }
|
||||
if (-not (Test-Path -LiteralPath $AuroraDirectory -PathType Container)) { return '' }
|
||||
$root = [IO.Path]::GetFullPath($AuroraDirectory).TrimEnd('\')
|
||||
$excludedPrefixes = @(
|
||||
(Join-Path $root 'extern') + '\',
|
||||
(Join-Path $root 'build') + '\'
|
||||
)
|
||||
# Dot-paths (the submodule's .git pointer) are skipped by name, not by the hidden attribute:
|
||||
# the payload zip drops that attribute, so the installed side would otherwise hash them.
|
||||
$files = Get-ChildItem -LiteralPath $root -Recurse -File -Force |
|
||||
Where-Object {
|
||||
$full = $_.FullName
|
||||
-not ($excludedPrefixes | Where-Object { $full.StartsWith($_, [StringComparison]::OrdinalIgnoreCase) }) -and
|
||||
-not ($full.Substring($root.Length + 1) -split '\\' | Where-Object { $_.StartsWith('.') })
|
||||
} |
|
||||
Sort-Object { $_.FullName.Substring($root.Length + 1).Replace('\', '/') }
|
||||
$sha = [Security.Cryptography.SHA256]::Create()
|
||||
return Get-MkwSourceTreeFingerprint $AuroraDirectory @('extern', 'build')
|
||||
}
|
||||
|
||||
function Resolve-MkwNativePrebuiltDirectory([string]$DependenciesDirectory, [string]$ToolchainBin,
|
||||
[string]$AuroraDirectory, [string]$ThirdPartyDirectory) {
|
||||
<#
|
||||
The shipped precompiled aurora/third-party package, verified against its recorded provenance
|
||||
(exact compiler, exact flags, sources) before use. Anything unexpected falls back to building
|
||||
from source. Shared with Build-Installer.ps1, which runs it against the staged payload under
|
||||
powershell.exe so a package users would reject never ships.
|
||||
#>
|
||||
$package = Join-Path $DependenciesDirectory 'native_prebuilt'
|
||||
$provenancePath = Join-Path $package 'provenance.json'
|
||||
if (-not (Test-Path -LiteralPath $provenancePath -PathType Leaf)) {
|
||||
Write-Host 'MKWCBUILD: No precompiled aurora package was shipped; building it from source'
|
||||
return ''
|
||||
}
|
||||
try {
|
||||
$builder = [Text.StringBuilder]::new()
|
||||
foreach ($file in $files) {
|
||||
$relative = $file.FullName.Substring($root.Length + 1).Replace('\', '/')
|
||||
$content = Get-MkwFileSha256 $file.FullName
|
||||
[void]$builder.Append($relative).Append(' ').Append($content).Append("`n")
|
||||
$provenance = Get-Content -LiteralPath $provenancePath -Raw | ConvertFrom-Json
|
||||
if ($provenance.CompilerSha256 -ne (Get-MkwFileSha256 (Join-Path $ToolchainBin 'clang-22.exe'))) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built by a different compiler; building it from source'
|
||||
return ''
|
||||
}
|
||||
$bytes = $sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($builder.ToString()))
|
||||
} finally { $sha.Dispose() }
|
||||
return (($bytes | ForEach-Object { $_.ToString('x2') }) -join '')
|
||||
if ($provenance.FlagFingerprint -ne (Get-MkwNativeFlagFingerprint)) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built with different flags; building it from source'
|
||||
return ''
|
||||
}
|
||||
# The archives embed Dawn's headers and link its import library; a different Dawn is an
|
||||
# ABI mismatch that only shows up as a crash inside the GPU backend.
|
||||
$recordedDawn = $provenance.PSObject.Properties['DawnRuntimeSha256']
|
||||
if ($null -eq $recordedDawn -or
|
||||
$recordedDawn.Value -ne (Get-MkwDawnRuntimeSha256 $DependenciesDirectory)) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built against a different Dawn; building it from source'
|
||||
return ''
|
||||
}
|
||||
$recordedAurora = $provenance.PSObject.Properties['AuroraSourceFingerprint']
|
||||
if ($null -eq $recordedAurora -or
|
||||
$recordedAurora.Value -ne (Get-MkwAuroraSourceFingerprint $AuroraDirectory)) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built from different aurora sources; building it from source'
|
||||
return ''
|
||||
}
|
||||
$recordedThirdParty = $provenance.PSObject.Properties['ThirdPartySourceFingerprint']
|
||||
if ($null -eq $recordedThirdParty -or
|
||||
$recordedThirdParty.Value -ne (Get-MkwThirdPartySourceFingerprint $ThirdPartyDirectory)) {
|
||||
Write-Host 'MKWCBUILD: The precompiled aurora package was built from different vendored third-party sources; building it from source'
|
||||
return ''
|
||||
}
|
||||
} catch {
|
||||
Write-Host "MKWCBUILD: The precompiled aurora package could not be validated ($($_.Exception.Message)); building it from source"
|
||||
return ''
|
||||
}
|
||||
Write-Host 'MKWCBUILD: Using the precompiled aurora and third-party libraries'
|
||||
return $package
|
||||
}
|
||||
|
||||
function ConvertTo-MkwCMakePath([string]$Path) {
|
||||
@@ -347,9 +411,9 @@ function Get-MkwNativeConfigureArguments {
|
||||
}
|
||||
}
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($NativePrebuiltDirectory)) {
|
||||
$arguments += "-DMKW_NATIVE_PREBUILT_DIR=$(ConvertTo-MkwCMakePath $NativePrebuiltDirectory)"
|
||||
}
|
||||
# Always set, so a reused CMake cache can never keep a package this run rejected.
|
||||
$arguments += if ([string]::IsNullOrWhiteSpace($NativePrebuiltDirectory)) { '-DMKW_NATIVE_PREBUILT_DIR=' }
|
||||
else { "-DMKW_NATIVE_PREBUILT_DIR=$(ConvertTo-MkwCMakePath $NativePrebuiltDirectory)" }
|
||||
|
||||
$arguments += $AdditionalArguments
|
||||
return $arguments
|
||||
|
||||
Reference in New Issue
Block a user