+function Set-NativeNinjaFirst {
+ # Make the native ninja.exe the one that wins, including inside a Visual
+ # Studio Developer Command Prompt.
+ #
+ # WHY THIS IS INSURANCE RATHER THAN THE FIX. VS ships an x64 ninja.exe even on
+ # ARM64 and puts it on the PATH from
+ # Common7\Tools\vsdevcmd\ext\cmake.bat, which does:
+ # set "PATH=%PATH%;...\CMake\bin;...\CMake\Ninja"
+ # That APPENDS - the VS directories land at the very end of the composed
+ # PATH, behind every machine and user entry. So a native ninja installed
+ # anywhere on the user PATH already beats it, and measurement on an ARM64 box
+ # confirms it does. (An earlier revision of this script claimed VsDevCmd
+ # prepends and that the VS copy therefore always won; that was wrong.)
+ #
+ # It is still worth pinning the order explicitly: winget appends its package
+ # directory to the user PATH, so the margin depends on nothing more than two
+ # append orders staying as they are, in a file Microsoft owns and revises.
+ # Putting the directory first costs nothing and removes the dependency.
+ #
+ # Ninja is worth this attention where a one-off tool would not be: it is
+ # re-invoked for every edge in the build graph, so it is the one place an
+ # emulated binary is paid over and over rather than once.
+ Write-Step 'Native ninja ahead of the Visual Studio copy'
+
+ $candidates = @()
+ $candidates += Get-ChildItem (Join-Path $env:LOCALAPPDATA 'Microsoft\WinGet\Packages') `
+ -Filter 'ninja.exe' -Recurse -Depth 2 -ErrorAction SilentlyContinue |
+ ForEach-Object { $_.FullName }
+ $candidates += @(
+ (Join-Path $env:ProgramFiles 'Ninja\ninja.exe')
+ (Join-Path $env:LOCALAPPDATA 'Programs\Ninja\ninja.exe')
+ )
+ # A ninja already on the PATH counts too - but only if it is not the VS one,
+ # which is the binary this step exists to get out in front of.
+ $onPath = (Get-Command ninja.exe -ErrorAction SilentlyContinue | Select-Object -First 1).Source
+ if ($onPath -and $onPath -notmatch 'CommonExtensions\\Microsoft\\CMake') { $candidates += $onPath }
+
+ $native = $null
+ foreach ($c in ($candidates | Where-Object { $_ -and (Test-Path $_) } | Select-Object -Unique)) {
+ $m = Get-PEMachine $c
+ if ($m -eq $(if ($IsArm64) { 'ARM64' } else { 'x64' })) { $native = $c; break }
+ }
+
+ if (-not $native) {
+ Write-Warning 'No native ninja.exe found. Install it with: winget install Ninja-build.Ninja'
+ Write-Warning 'Until then a build using the Ninja generator gets the x64 ninja Visual Studio bundles.'
+ return
+ }
+
+ Write-Host " native ninja: $native ($(Get-PEMachine $native))"
+ Add-ToUserPath (Split-Path $native -Parent) -Prepend
+}
+