Add Windows x86-32 emulation support to interpreter architecture checks (#13475)

Closes https://github.com/astral-sh/uv/issues/13471

Refactors the logic there a bit too.

---------

Co-authored-by: Aria Desires <aria.desires@gmail.com>
This commit is contained in:
Zanie Blue 2025-10-30 09:50:26 -05:00 committed by GitHub
parent c7aaa8b7ef
commit a1610c794e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 94 additions and 7 deletions

View file

@ -3,6 +3,7 @@
use std::cmp;
use std::fmt;
use std::str::FromStr;
use target_lexicon::Architecture;
use thiserror::Error;
use tracing::trace;
@ -91,13 +92,28 @@ impl Platform {
return true;
}
// Windows ARM64 runs emulated x86_64 binaries transparently
// Similarly, macOS aarch64 runs emulated x86_64 binaries transparently if you have Rosetta
// installed. We don't try to be clever and check if that's the case here, we just assume
// that if x86_64 distributions are available, they're usable.
if (self.os.is_windows() || self.os.is_macos())
&& matches!(self.arch.family(), target_lexicon::Architecture::Aarch64(_))
&& matches!(other.arch.family(), target_lexicon::Architecture::X86_64)
#[allow(clippy::unnested_or_patterns)]
if self.os.is_windows()
&& matches!(
(self.arch.family(), other.arch.family()),
// 32-bit x86 binaries work fine on 64-bit x86 windows
(Architecture::X86_64, Architecture::X86_32(_)) |
// Both 32-bit and 64-bit binaries are transparently emulated on aarch64 windows
(Architecture::Aarch64(_), Architecture::X86_64) |
(Architecture::Aarch64(_), Architecture::X86_32(_))
)
{
return true;
}
if self.os.is_macos()
&& matches!(
(self.arch.family(), other.arch.family()),
// macOS aarch64 runs emulated x86_64 binaries transparently if you have Rosetta
// installed. We don't try to be clever and check if that's the case here,
// we just assume that if x86_64 distributions are available, they're usable.
(Architecture::Aarch64(_), Architecture::X86_64)
)
{
return true;
}

View file

@ -2765,6 +2765,77 @@ fn python_install_emulated_macos() {
");
}
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
#[test]
fn python_install_emulated_windows_x86_on_x64() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
// Before installation, `uv python list` should not show the x86_32 download
uv_snapshot!(context.filters(), context.python_list().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.9-windows-x86_64-none <download available>
----- stderr -----
");
// Install an x86_32 version (assuming an x64 host)
uv_snapshot!(context.filters(), context.python_install().arg("3.13-x86"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.9 in [TIME]
+ cpython-3.13.9-windows-x86-none (python3.13)
");
// It should be discoverable with `uv python find`
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13.9-windows-x86-none/python
----- stderr -----
");
// And included in `uv python list`
uv_snapshot!(context.filters(), context.python_list().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.9-windows-x86_64-none <download available>
cpython-3.13.9-windows-x86-none managed/cpython-3.13.9-windows-x86-none/python
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13-x86_64"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.9 in [TIME]
+ cpython-3.13.9-windows-x86_64-none
");
// Once we've installed the native version, it should be preferred over x86_32
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13.9-windows-x86_64-none/python
----- stderr -----
");
}
// A virtual environment should track the latest patch version installed.
#[test]
fn install_transparent_patch_upgrade_uv_venv() {