From a331e6f592641b30c6ffc51c5b74675eb4fb48d5 Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Sat, 20 Jun 2026 16:47:49 -0700 Subject: [PATCH 1/6] Exit after `versions --update` instead of falling through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The argparse block in pyversions.main exits cleanly after `--update-deps` but `--update` had no `sys.exit(0)`, so it fell through into the `if args.version:` block. `--version` defaults to "3.14", so every `relenv versions --update` run ended by printing the latest 3.14.x — mistakable for "I just added 3.14.6" output when really it was just the implicit version lookup running. Mirror the --update-deps shape: exit after the update finishes. --- relenv/pyversions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/relenv/pyversions.py b/relenv/pyversions.py index cd504f08..e8a2f99e 100644 --- a/relenv/pyversions.py +++ b/relenv/pyversions.py @@ -1418,6 +1418,7 @@ def main(args: argparse.Namespace) -> None: if args.update: python_versions(create=True) + sys.exit(0) if args.list: for version in python_versions(): print(version) From dd3d63f6eb3ef8566bd07d07d30cc0c73be0867f Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Sun, 21 Jun 2026 16:15:43 -0700 Subject: [PATCH 2/6] Install v140 toolset on existing VS via VS bootstrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous attempt invoked vs_installer.exe with an explicitly-quoted installPath; it bailed with exit 87 (invalid parameter). Two changes: - Use `Installer\setup.exe` (the VS bootstrapper) and fall back to vs_installer.exe. setup.exe is what Microsoft documents as the bootstrapper for modify operations. - Pass --installPath as a bare PowerShell argument (let Start-Process quote it), drop the manual backtick-quotes that confused the parser. Also stop trusting the bootstrapper's exit code — VS Installer returns non-zero in several benign cases. Verify by checking that MSBuild can see the v140 platform toolset: ${env:ProgramFiles(x86)}\MSBuild\Microsoft.Cpp\v4.0\V140 If that path exists after the modify call, the toolset is registered and Python's PCbuild can use it. --- relenv/_scripts/install_vc_build.ps1 | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/relenv/_scripts/install_vc_build.ps1 b/relenv/_scripts/install_vc_build.ps1 index 5528ca7e..2745abb8 100644 --- a/relenv/_scripts/install_vc_build.ps1 +++ b/relenv/_scripts/install_vc_build.ps1 @@ -109,6 +109,48 @@ Write-Host "Confirming Presence of Visual Studio Build Tools: " -NoNewline # We're only gonna look for msbuild.exe if ( Test-Path -Path $MSBUILD_BIN ) { Write-Result "Success" -ForegroundColor Green + + # MSBuild is present, but Python's PCbuild for 3.10/3.11 pins + # PlatformToolset to v140. Current windows-latest runners ship VS + # without v140 by default, so use the VS bootstrapper to add the + # component to the existing install. We don't trust the installer's + # exit code (it returns non-zero in a few benign cases) — instead + # verify the v140 platform-toolset targets file exists afterwards. + $V140_TARGETS = "${env:ProgramFiles(x86)}\MSBuild\Microsoft.Cpp\v4.0\V140" + Write-Host "Ensuring v140 toolset is installed: " -NoNewline + if ( Test-Path -Path $V140_TARGETS ) { + Write-Result "Already present" -ForegroundColor Green + } else { + Write-Host "" + $VS_BOOTSTRAPPER = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe" + if ( -not (Test-Path -Path $VS_BOOTSTRAPPER) ) { + $VS_BOOTSTRAPPER = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vs_installer.exe" + } + if ( -not (Test-Path -Path $VS_BOOTSTRAPPER) ) { + Write-Host " VS bootstrapper not found under Microsoft Visual Studio\Installer" + exit 1 + } + $installer_args = @( + "modify", + "--installPath", $VS_INST_LOC, + "--add", "Microsoft.VisualStudio.Component.VC.140", + "--add", "Microsoft.VisualStudio.Component.Windows81SDK", + "--quiet", "--norestart", "--wait", "--nocache" + ) + Write-Host " Running: $VS_BOOTSTRAPPER $($installer_args -join ' ')" + $proc = Start-Process ` + -FilePath $VS_BOOTSTRAPPER ` + -ArgumentList $installer_args ` + -PassThru -Wait -NoNewWindow + Write-Host " bootstrapper exit code: $($proc.ExitCode)" + Write-Host "Verifying v140 toolset: " -NoNewline + if ( Test-Path -Path $V140_TARGETS ) { + Write-Result "Success" -ForegroundColor Green + } else { + Write-Result "Failed (v140 still not registered with MSBuild)" -ForegroundColor Red + exit 1 + } + } } else { Write-Result "Missing" -ForegroundColor Yellow From d4d38612d3d4c430d3690917cc3b0f5fee5efb16 Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Sun, 21 Jun 2026 16:46:27 -0700 Subject: [PATCH 3/6] Pass installer cmdline as single string so quoted path survives Previous attempt passed the bootstrapper arguments as a PowerShell array; Start-Process then concatenated them without re-quoting, so `C:\Program Files\Microsoft Visual Studio\18\Enterprise` was parsed as separate positional arguments and the installer rejected the call with exit 87. Build the command line as a single string with embedded double quotes around $VS_INST_LOC. Start-Process forwards that verbatim, the installer sees a properly-quoted --installPath, and the modify operation proceeds. --- relenv/_scripts/install_vc_build.ps1 | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/relenv/_scripts/install_vc_build.ps1 b/relenv/_scripts/install_vc_build.ps1 index 2745abb8..a4928440 100644 --- a/relenv/_scripts/install_vc_build.ps1 +++ b/relenv/_scripts/install_vc_build.ps1 @@ -130,17 +130,15 @@ if ( Test-Path -Path $MSBUILD_BIN ) { Write-Host " VS bootstrapper not found under Microsoft Visual Studio\Installer" exit 1 } - $installer_args = @( - "modify", - "--installPath", $VS_INST_LOC, - "--add", "Microsoft.VisualStudio.Component.VC.140", - "--add", "Microsoft.VisualStudio.Component.Windows81SDK", - "--quiet", "--norestart", "--wait", "--nocache" - ) - Write-Host " Running: $VS_BOOTSTRAPPER $($installer_args -join ' ')" + # Pass the entire command line as a single string so the embedded + # quotes around --installPath survive Start-Process intact. Passing + # an array would let Start-Process drop the quotes and the + # bootstrapper would parse "C:\Program" as the installPath value. + $installer_cmdline = 'modify --installPath "{0}" --add Microsoft.VisualStudio.Component.VC.140 --add Microsoft.VisualStudio.Component.Windows81SDK --quiet --norestart --wait --nocache' -f $VS_INST_LOC + Write-Host " Running: $VS_BOOTSTRAPPER $installer_cmdline" $proc = Start-Process ` -FilePath $VS_BOOTSTRAPPER ` - -ArgumentList $installer_args ` + -ArgumentList $installer_cmdline ` -PassThru -Wait -NoNewWindow Write-Host " bootstrapper exit code: $($proc.ExitCode)" Write-Host "Verifying v140 toolset: " -NoNewline From 1b7baf3bd50a79d48f971732fcd7ae85882b64c6 Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Sun, 21 Jun 2026 17:46:20 -0700 Subject: [PATCH 4/6] Drop invalid --wait flag from VS Installer modify call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified against the real Visual Studio Installer (4.x) on a Windows 11 box: passing --wait makes the bootstrapper bail before parsing anything else with "Option 'wait' is unknown" and exit code 87 — the mystery exit-87 we kept hitting in CI. --quiet already runs the modify synchronously, and Start-Process -Wait in PowerShell still ensures we don't return until the bootstrapper process exits. Tested locally: the full install_vc_build.ps1 -CICD now reports "Ensuring v140 toolset is installed: Already present" on an existing VS install, and the standalone modify call returns exit 0. --- relenv/_scripts/install_vc_build.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/relenv/_scripts/install_vc_build.ps1 b/relenv/_scripts/install_vc_build.ps1 index a4928440..314a9682 100644 --- a/relenv/_scripts/install_vc_build.ps1 +++ b/relenv/_scripts/install_vc_build.ps1 @@ -134,7 +134,11 @@ if ( Test-Path -Path $MSBUILD_BIN ) { # quotes around --installPath survive Start-Process intact. Passing # an array would let Start-Process drop the quotes and the # bootstrapper would parse "C:\Program" as the installPath value. - $installer_cmdline = 'modify --installPath "{0}" --add Microsoft.VisualStudio.Component.VC.140 --add Microsoft.VisualStudio.Component.Windows81SDK --quiet --norestart --wait --nocache' -f $VS_INST_LOC + # `setup.exe modify` does NOT accept --wait (verified against + # Visual Studio Installer 4.x — `Option 'wait' is unknown`). + # --quiet already runs synchronously, and Start-Process -Wait + # below ensures we don't return until the bootstrapper exits. + $installer_cmdline = 'modify --installPath "{0}" --add Microsoft.VisualStudio.Component.VC.140 --add Microsoft.VisualStudio.Component.Windows81SDK --quiet --norestart --nocache' -f $VS_INST_LOC Write-Host " Running: $VS_BOOTSTRAPPER $installer_cmdline" $proc = Start-Process ` -FilePath $VS_BOOTSTRAPPER ` From bae46363541c72fe25bd222bf20c0051ff5bfd27 Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Sun, 21 Jun 2026 18:12:32 -0700 Subject: [PATCH 5/6] Pair v140 with Windows 10 SDK 19041 instead of nonexistent Windows81SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After v140 install succeeded, Python 3.11.15 PCbuild started failing on the windows-latest runner with: \ucrt\wchar.h(443): error C2440: 'initializing': cannot convert from 'int' to '__m128i' Two related causes, both fixed here: - The bootstrapper was warning "Cannot find package: Microsoft.VisualStudio.Component.Windows81SDK in product graph" — that component was removed in VS 2022+ / VS 18. No SDK was actually installed alongside v140, so PCbuild fell back to the runner's only SDK (Win11 SDK 10.0.26100.0), whose uses SSE intrinsics that v140 chokes on. - Even with an older SDK installed, MSBuild auto-picks the newest one unless told otherwise. Install `Windows10SDK.19041` (Win10 SDK 2004, the latest known to pair cleanly with v140 and Python's PCbuild) and pin the build step to it via `WindowsTargetPlatformVersion`. --- .github/workflows/build-native-action.yml | 5 +++++ relenv/_scripts/install_vc_build.ps1 | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-native-action.yml b/.github/workflows/build-native-action.yml index aefe1eed..88e3db9d 100644 --- a/.github/workflows/build-native-action.yml +++ b/.github/workflows/build-native-action.yml @@ -317,6 +317,11 @@ jobs: - name: Build Python with Relenv env: RELENV_NATIVE_PY_VERSION: 3.10.15 + # Pin MSBuild to the older Windows 10 SDK we just installed + # alongside v140; the newer 26100 SDK on windows-latest has + # SSE intrinsics in that break C compiles under the + # v140 toolset Python 3.10/3.11 PCbuild targets. + WindowsTargetPlatformVersion: "10.0.19041.0" run: | python -m relenv build --no-pretty --arch=${{ matrix.arch }} --python=${{ steps.python-version.outputs.version }} diff --git a/relenv/_scripts/install_vc_build.ps1 b/relenv/_scripts/install_vc_build.ps1 index 314a9682..eb4256f2 100644 --- a/relenv/_scripts/install_vc_build.ps1 +++ b/relenv/_scripts/install_vc_build.ps1 @@ -138,7 +138,12 @@ if ( Test-Path -Path $MSBUILD_BIN ) { # Visual Studio Installer 4.x — `Option 'wait' is unknown`). # --quiet already runs synchronously, and Start-Process -Wait # below ensures we don't return until the bootstrapper exits. - $installer_cmdline = 'modify --installPath "{0}" --add Microsoft.VisualStudio.Component.VC.140 --add Microsoft.VisualStudio.Component.Windows81SDK --quiet --norestart --nocache' -f $VS_INST_LOC + # Pair v140 with the Windows 10 SDK 19041 (the latest SDK known + # to compile cleanly against the v140 toolset and Python 3.10/3.11 + # PCbuild headers; newer SDKs put SSE intrinsics in + # that v140 chokes on with C2440). Windows81SDK is not present + # in the VS 2022+/VS 18 product graph and silently no-op'd here. + $installer_cmdline = 'modify --installPath "{0}" --add Microsoft.VisualStudio.Component.VC.140 --add Microsoft.VisualStudio.Component.Windows10SDK.19041 --quiet --norestart --nocache' -f $VS_INST_LOC Write-Host " Running: $VS_BOOTSTRAPPER $installer_cmdline" $proc = Start-Process ` -FilePath $VS_BOOTSTRAPPER ` From e313feca333fe05d2685041da332a3567e0a2021 Mon Sep 17 00:00:00 2001 From: "Daniel A. Wozniak" Date: Tue, 23 Jun 2026 01:08:13 -0700 Subject: [PATCH 6/6] Pin Windows build runners to windows-2022 windows-latest has rolled to VS 18 (a.k.a. VS 2026), whose VS Installer product graph no longer exposes pre-26100 Windows SDKs by component name. We need v140 + an older Windows SDK to compile Python 3.10/3.11 PCbuild (newer SDKs put SSE intrinsics in that v140 chokes on with C2440), but on VS 18 we can't get there: Warning: Cannot find package: Microsoft.VisualStudio.Component.Windows10SDK.19041 in product graph. error MSB8036: The Windows SDK version 10.0.19041.0 was not found. windows-2022 still ships VS 2022 with multiple Windows SDKs (10240, 19041, 20348, 22621, 26100), so v140 + the env-var pin to 10.0.19041.0 works there. Pin both build_windows and the matching verify test_windows to that image until a path forward exists for VS 18. The install-v140/SDK-19041 helper in install_vc_build.ps1 and the WindowsTargetPlatformVersion env var stay in place: on windows-2022 the v140 check is a no-op (it's pre-installed), and the env var pins MSBuild to the SDK that v140 expects. --- .github/workflows/build-native-action.yml | 9 ++++++++- .github/workflows/verify-build-action.yml | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-native-action.yml b/.github/workflows/build-native-action.yml index 88e3db9d..acb671ea 100644 --- a/.github/workflows/build-native-action.yml +++ b/.github/workflows/build-native-action.yml @@ -263,7 +263,14 @@ jobs: build_windows: name: "Python Windows" - runs-on: windows-latest + # Pinned to windows-2022 deliberately. windows-latest has rolled to + # VS 18 / VS 2026, whose product graph only exposes Win11 SDK 26100 + # (Microsoft.VisualStudio.Component.Windows10SDK.19041 etc. are + # silently no-op'd by the VS Installer there). Win10 SDK 26100 uses + # SSE intrinsics in that v140 (which Python 3.10/3.11 + # PCbuild pin to) chokes on, breaking the build. windows-2022 still + # ships VS 2022 plus multiple older SDKs that pair cleanly with v140. + runs-on: windows-2022 strategy: fail-fast: false matrix: diff --git a/.github/workflows/verify-build-action.yml b/.github/workflows/verify-build-action.yml index 558ac7ff..df8c9552 100644 --- a/.github/workflows/verify-build-action.yml +++ b/.github/workflows/verify-build-action.yml @@ -212,7 +212,9 @@ jobs: test_windows: name: "Verify Windows" - runs-on: windows-latest + # Match the build runner (windows-2022) — see build-native-action.yml + # for why we don't use windows-latest. + runs-on: windows-2022 strategy: fail-fast: false