mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-05-18 05:05:25 +02:00
build: discover VS 2026 Insiders and exclude BuildTools in vswhere lookup (#47462)
## Summary of the Pull Request Fixes `tools\build\build-common.ps1` so a clean `tools\build\build-essentials.cmd` (or `build.ps1`) run discovers and uses **Visual Studio 2026 Insiders** without any manual `Enter-VsDevShell` preamble. Today the script lands on the first VS 2022 BuildTools instance it finds (which lacks the C++ workload) and every native `.vcxproj` errors with `MSB4086: $(PlatformToolsetVersion) evaluates to ""` during NuGet restore. Two scoped commits, **only `tools\build\build-common.ps1` is touched** (+58 / −36 net). ## PR Checklist - [ ] Closes: #xxx - [x] **Communication:** I''ve discussed this with core contributors already. If the work hasn''t been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places (n/a — build-script change only) - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx ## Detailed Description of the Pull Request / Additional comments ### What''s broken `build-common.ps1`''s `vswhere` lookup runs **without `-prerelease`**, so VS 2026 Insiders / Preview installs are invisible to it. The explicit fallback path list also only contains VS 2022 entries. On a machine that has VS 2022 BuildTools (typical for CI hosts and many dev boxes) but only has VS 2026 in *Insiders* form, the script: 1. Picks `C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools` because it''s a candidate `vswhere` returned and it''s in the fallback list. 2. Enters its DevShell — but BuildTools has no C++ workload installed, so `$(VCToolsInstallDir)` and `$(PlatformToolsetVersion)` are unset. 3. NuGet restore over `PowerToys.slnx` fans out to every `.vcxproj` and they each hit `Microsoft.CodeAnalysis.targets(401,15): error MSB4086: A numeric comparison was attempted on "$(PlatformToolsetVersion)" that evaluates to "" instead of a number, in condition "''$(PlatformToolsetVersion)''<''120''".` The build dies before any project compiles. This was reproduced today against `origin/main` — confirming this is a pre-existing breakage independent of any in-flight feature work. ### What this PR changes Commit **`30acf72c` — Fix build scripts to discover VS 2026 / Insiders installations** - Adds `-prerelease` to `vswhere` calls, tried **before** the stable lookup so prerelease VS is preferred when it''s the only one with a working C++ workload. - Adds VS 2026 year-name and internal-version (`18\Insiders`) paths to the explicit fallback list. - Keeps VS 2022 paths as the final fallback so existing setups keep working. - Priority order: `prerelease+VC tools` → `prerelease` → `stable+VC tools` → `stable`. Commit **`18b27209` — build: simplify VS environment initialization with VS2022/VS2026 support** - Adds `-prerelease` to `vswhere` (consolidates with the above; the prerelease query subsumes the stable one now). - Restricts the SKU query to `Community` / `Professional` / `Enterprise` (explicitly excludes `BuildTools`) so the script can no longer accidentally pick a SKU without the C++ workload. - Reduces vswhere from **4 calls to 2**. - Removes the destructive BuildTools env-var cleanup block (no longer needed once vswhere refuses to return BuildTools in the first place). - Adds `VsDevCmd.bat` exit-code validation so a partial DevShell init fails loudly instead of silently producing a half-initialized environment. - Adds VS 2022 / VS 2026 Preview entries to the explicit fallback list. ### Why two commits instead of a squash The first commit is the minimum-viable fix that addresses the reported MSB4086 failure. The second commit is a follow-up cleanup that''s only safe **once** prerelease is preferred and BuildTools is excluded. Splitting them keeps each commit independently revert-able if a regression shows up on a specific dev environment shape. ## Validation Steps Performed | Step | Result | |---|---| | Reproduce on `main`: cold `tools\build\build-essentials.cmd` in a non-DevShell PowerShell | **MSB4086** on `Microsoft.CommandPalette.Extensions.vcxproj`, `Microsoft.Terminal.UI.vcxproj`, `PowerToys.MeasureToolCore.vcxproj`, `PowerRenameUI.vcxproj` — confirmed broken | | With this branch checked out: same cold `build-essentials.cmd` invocation | `[VS] vswhere found: ... C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe` → `[VS] Checking candidate: C:\Program Files\Microsoft Visual Studio\18\Insiders` → `[VS] Entered Visual Studio DevShell at C:\Program Files\Microsoft Visual Studio\18\Insiders` — VS 2026 Insiders selected directly, restore step proceeds past the MSB4086 wall | | Manual workaround pre-init via `Import-Module Microsoft.VisualStudio.DevShell.dll` + `Enter-VsDevShell` | Now **unnecessary** — the script self-initializes correctly | After this fix, the next failure mode the build hits is unrelated NuGet feed coverage for in-flight WinAppSDK upgrade work, which is the gated dependency this PR was extracted from to keep this change atomic. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -176,11 +176,22 @@ function Get-DefaultPlatform {
|
||||
return 'x64'
|
||||
}
|
||||
|
||||
function Test-VsHasNativeTools {
|
||||
# Returns $true when the current process environment was initialized with a
|
||||
# usable native (C++) toolchain. Any VS instance (full SKU or Build Tools)
|
||||
# without the C++ workload leaves these unset, which is the original
|
||||
# MSB4086 ($(PlatformToolsetVersion) empty) failure mode we are guarding
|
||||
# against.
|
||||
if (-not $env:VCToolsInstallDir) { return $false }
|
||||
if (-not (Test-Path $env:VCToolsInstallDir)) { return $false }
|
||||
return $true
|
||||
}
|
||||
|
||||
function Ensure-VsDevEnvironment {
|
||||
$OriginalLocationForVsInit = Get-Location
|
||||
try {
|
||||
|
||||
if ($env:VSINSTALLDIR -or $env:VCINSTALLDIR -or $env:DevEnvDir -or $env:VCToolsInstallDir) {
|
||||
if ($env:VSINSTALLDIR -or $env:VCINSTALLDIR) {
|
||||
Write-Host "[VS] VS developer environment already present"
|
||||
return $true
|
||||
}
|
||||
@@ -193,22 +204,44 @@ function Ensure-VsDevEnvironment {
|
||||
$vswhere = $vswhereCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
|
||||
if ($vswhere) { Write-Host "[VS] vswhere found: $vswhere" } else { Write-Host "[VS] vswhere not found" }
|
||||
|
||||
# Probe for a Visual Studio install with the C++ workload. Selection is
|
||||
# capability-based (-requires VC.Tools.x86.x64), not SKU-based: full VS
|
||||
# SKUs and Build Tools are equally valid as long as the C++ workload is
|
||||
# installed. -prerelease lets vswhere see Preview/Insiders alongside GA.
|
||||
$vsProducts = @('Microsoft.VisualStudio.Product.Community',
|
||||
'Microsoft.VisualStudio.Product.Professional',
|
||||
'Microsoft.VisualStudio.Product.Enterprise',
|
||||
'Microsoft.VisualStudio.Product.BuildTools')
|
||||
|
||||
$instPaths = @()
|
||||
if ($vswhere) {
|
||||
# First try with the VC tools requirement (preferred)
|
||||
try { $p = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath 2>$null; if ($p) { $instPaths += $p } } catch {}
|
||||
# Fallback: try without -requires to find any VS installations
|
||||
# Newest VS instance with the C++ VC tools workload (stable + prerelease).
|
||||
try { $p = & $vswhere -latest -prerelease -products $vsProducts -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath 2>$null; if ($p) { $instPaths += $p } } catch {}
|
||||
# Last-resort fallback if no instance reports the VC workload (still
|
||||
# validated below by Test-VsHasNativeTools to skip unusable installs).
|
||||
if (-not $instPaths) {
|
||||
try { $p2 = & $vswhere -latest -products * -property installationPath 2>$null; if ($p2) { $instPaths += $p2 } } catch {}
|
||||
try { $p2 = & $vswhere -latest -prerelease -products $vsProducts -property installationPath 2>$null; if ($p2) { $instPaths += $p2 } } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
# Add explicit common year-based candidates as a last resort
|
||||
# Add explicit common candidates as a last resort (newest first)
|
||||
if (-not $instPaths) {
|
||||
$explicit = @(
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2026\Insiders",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2026\Preview",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2026\Community",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2026\Professional",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2026\Enterprise",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\18\Insiders",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\18\Preview",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\18\Community",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\18\Professional",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\18\Enterprise",
|
||||
"$env:ProgramFiles (x86)\Microsoft Visual Studio\2022\Preview",
|
||||
"$env:ProgramFiles (x86)\Microsoft Visual Studio\2022\Community",
|
||||
"$env:ProgramFiles (x86)\Microsoft Visual Studio\2022\Professional",
|
||||
"$env:ProgramFiles (x86)\Microsoft Visual Studio\2022\Enterprise",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2022\Preview",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2022\Community",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2022\Professional",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2022\Enterprise"
|
||||
@@ -221,7 +254,8 @@ function Ensure-VsDevEnvironment {
|
||||
return $false
|
||||
}
|
||||
|
||||
# Try each candidate installation path until one works
|
||||
# Try each candidate installation path until one yields a working native
|
||||
# toolchain (validated post-init via Test-VsHasNativeTools).
|
||||
foreach ($inst in $instPaths) {
|
||||
if (-not $inst) { continue }
|
||||
Write-Host "[VS] Checking candidate: $inst"
|
||||
@@ -234,6 +268,10 @@ function Ensure-VsDevEnvironment {
|
||||
# Call Enter-VsDevShell using only the install path to avoid parameter name differences
|
||||
try {
|
||||
Enter-VsDevShell -VsInstallPath $inst -ErrorAction Stop
|
||||
if (-not (Test-VsHasNativeTools)) {
|
||||
Write-Warning "[VS] DevShell entered $inst but VC tools (VCToolsInstallDir) not present - skipping"
|
||||
continue
|
||||
}
|
||||
Write-Host "[VS] Entered Visual Studio DevShell at $inst"
|
||||
return $true
|
||||
} catch {
|
||||
@@ -249,12 +287,20 @@ function Ensure-VsDevEnvironment {
|
||||
Write-Host "[VS] Running VsDevCmd.bat and importing environment from $vsDevCmd"
|
||||
try {
|
||||
$cmdOut = cmd.exe /c "`"$vsDevCmd`" && set"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "[VS] VsDevCmd.bat exited with code $LASTEXITCODE at $inst"
|
||||
continue
|
||||
}
|
||||
foreach ($line in $cmdOut) {
|
||||
$parts = $line -split('=',2)
|
||||
if ($parts.Length -eq 2) {
|
||||
try { [Environment]::SetEnvironmentVariable($parts[0], $parts[1], 'Process') } catch {}
|
||||
}
|
||||
}
|
||||
if (-not (Test-VsHasNativeTools)) {
|
||||
Write-Warning "[VS] VsDevCmd.bat imported $inst but VC tools (VCToolsInstallDir) not present - skipping"
|
||||
continue
|
||||
}
|
||||
Write-Host "[VS] Imported environment from VsDevCmd.bat at $inst"
|
||||
return $true
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user