mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
disfavor aarch64 windows in its own house (#13724)
and prefer emulated x64 windows in its stead. This is preparatory work for shipping support for uv downloading and installing aarch64 (arm64) windows Pythons. We've [had builds for this platform ready for a while](https://github.com/astral-sh/python-build-standalone/pull/387), but have held back on shipping them due to a fundamental problem: **The Python packaging ecosystem does not have strong support for aarch64 windows**, e.g., not many projects build aarch64 wheels yet. The net effect of this is that, if we handed you an aarch64 python interpreter on windows, you would have to build a lot more sdists, and there's a high chance you will simply fail to build that sdist and be sad. Yes unfortunately, in this case a non-native Python interpreter simply *works better* than the native one... in terms of working at all, today. Of course, if the native interpreter works for your project, it should presumably have better performance and platform compatibility. We do not want to stand in the way of progress, as ideally this situation is a temporary state of affairs as the ecosystem grows to support aarch64 windows. To enable progress, on aarch64 Windows builds of uv: * We will still use a native python interpreter, e.g., if it's at the front of your `PATH` or the only installed version. * If we are choosing between equally good interpreters that differ in architecture, x64 will be preferred. * If the aarch64 version is newer, we will prefer the aarch64 one. * We will emit a diagnostic on installation, and show the python request to pass to uv to force aarch64 windows to be used. * Will be shipping [aarch64 Windows Python downloads](https://github.com/astral-sh/python-build-standalone/pull/387) * Will probably add some kind of global override setting/env-var to disable this behaviour. * Will be shipping this behaviour in [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) We're coordinating with Microsoft, GitHub (for the `setup-python` action), and the CPython team (for the `python.org` installers), to ensure we're aligned on this default and the timing of toggling to prefer native distributions in the future. See discussion in - https://github.com/astral-sh/uv/issues/12906 --- This is an alternative to * #13719 which uses sorting rather than filtering, as discussed in * #13721
This commit is contained in:
parent
1c7c174bc8
commit
317ce6e245
3 changed files with 98 additions and 6 deletions
22
.github/workflows/ci.yml
vendored
22
.github/workflows/ci.yml
vendored
|
@ -2090,6 +2090,28 @@ jobs:
|
|||
- name: "Validate global Python install"
|
||||
run: py -3.13 ./scripts/check_system_python.py --uv ./uv.exe
|
||||
|
||||
system-test-windows-aarch64-aarch64-python-313:
|
||||
timeout-minutes: 10
|
||||
needs: build-binary-windows-aarch64
|
||||
name: "check system | aarch64 python3.13 on windows aarch64"
|
||||
runs-on: github-windows-11-aarch64-4
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
architecture: "arm64"
|
||||
allow-prereleases: true
|
||||
|
||||
- name: "Download binary"
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: uv-windows-aarch64-${{ github.sha }}
|
||||
|
||||
- name: "Validate global Python install"
|
||||
run: py -3.13 ./scripts/check_system_python.py --uv ./uv.exe
|
||||
|
||||
# Test our PEP 514 integration that installs Python into the Windows registry.
|
||||
system-test-windows-registry:
|
||||
timeout-minutes: 10
|
||||
|
|
|
@ -43,15 +43,36 @@ impl Ord for Arch {
|
|||
return self.variant.cmp(&other.variant);
|
||||
}
|
||||
|
||||
let native = Arch::from_env();
|
||||
// For the time being, manually make aarch64 windows disfavored
|
||||
// on its own host platform, because most packages don't have wheels for
|
||||
// aarch64 windows, making emulation more useful than native execution!
|
||||
//
|
||||
// The reason we do this in "sorting" and not "supports" is so that we don't
|
||||
// *refuse* to use an aarch64 windows pythons if they happen to be installed
|
||||
// and nothing else is available.
|
||||
//
|
||||
// Similarly if someone manually requests an aarch64 windows install, we
|
||||
// should respect that request (this is the way users should "override"
|
||||
// this behaviour).
|
||||
let preferred = if cfg!(all(windows, target_arch = "aarch64")) {
|
||||
Arch {
|
||||
family: target_lexicon::Architecture::X86_64,
|
||||
variant: None,
|
||||
}
|
||||
} else {
|
||||
// Prefer native architectures
|
||||
Arch::from_env()
|
||||
};
|
||||
|
||||
// Prefer native architectures
|
||||
match (self.family == native.family, other.family == native.family) {
|
||||
match (
|
||||
self.family == preferred.family,
|
||||
other.family == preferred.family,
|
||||
) {
|
||||
(true, true) => unreachable!(),
|
||||
(true, false) => std::cmp::Ordering::Less,
|
||||
(false, true) => std::cmp::Ordering::Greater,
|
||||
(false, false) => {
|
||||
// Both non-native, fallback to lexicographic order
|
||||
// Both non-preferred, fallback to lexicographic order
|
||||
self.family.to_string().cmp(&other.family.to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Write;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -15,7 +16,9 @@ use tracing::{debug, trace};
|
|||
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_fs::Simplified;
|
||||
use uv_python::downloads::{self, DownloadResult, ManagedPythonDownload, PythonDownloadRequest};
|
||||
use uv_python::downloads::{
|
||||
self, ArchRequest, DownloadResult, ManagedPythonDownload, PythonDownloadRequest,
|
||||
};
|
||||
use uv_python::managed::{
|
||||
ManagedPythonInstallation, ManagedPythonInstallations, PythonMinorVersionLink,
|
||||
create_link_to_executable, python_executable_dir,
|
||||
|
@ -401,6 +404,7 @@ pub(crate) async fn install(
|
|||
|
||||
let mut errors = vec![];
|
||||
let mut downloaded = Vec::with_capacity(downloads.len());
|
||||
let mut requests_by_new_installation = BTreeMap::new();
|
||||
while let Some((download, result)) = tasks.next().await {
|
||||
match result {
|
||||
Ok(download_result) => {
|
||||
|
@ -412,10 +416,19 @@ pub(crate) async fn install(
|
|||
|
||||
let installation = ManagedPythonInstallation::new(path, download);
|
||||
changelog.installed.insert(installation.key().clone());
|
||||
for request in &requests {
|
||||
// Take note of which installations satisfied which requests
|
||||
if request.matches_installation(&installation) {
|
||||
requests_by_new_installation
|
||||
.entry(installation.key().clone())
|
||||
.or_insert(Vec::new())
|
||||
.push(request);
|
||||
}
|
||||
}
|
||||
if changelog.existing.contains(installation.key()) {
|
||||
changelog.uninstalled.insert(installation.key().clone());
|
||||
}
|
||||
downloaded.push(installation);
|
||||
downloaded.push(installation.clone());
|
||||
}
|
||||
Err(err) => {
|
||||
errors.push((download.key().clone(), anyhow::Error::new(err)));
|
||||
|
@ -529,6 +542,42 @@ pub(crate) async fn install(
|
|||
}
|
||||
|
||||
if !changelog.installed.is_empty() {
|
||||
for install_key in &changelog.installed {
|
||||
// Make a note if the selected python is non-native for the architecture,
|
||||
// if none of the matching user requests were explicit
|
||||
let native_arch = Arch::from_env();
|
||||
if install_key.arch().family() != native_arch.family() {
|
||||
let not_explicit =
|
||||
requests_by_new_installation
|
||||
.get(install_key)
|
||||
.and_then(|requests| {
|
||||
let all_non_explicit = requests.iter().all(|request| {
|
||||
if let PythonRequest::Key(key) = &request.request {
|
||||
!matches!(key.arch(), Some(ArchRequest::Explicit(_)))
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
if all_non_explicit {
|
||||
requests.iter().next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if let Some(not_explicit) = not_explicit {
|
||||
let native_request =
|
||||
not_explicit.download_request.clone().with_arch(native_arch);
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"{} uv selected a Python distribution with an emulated architecture ({}) for your platform because support for the native architecture ({}) is not yet mature; to override this behaviour, request the native architecture explicitly with: {}",
|
||||
"note:".bold(),
|
||||
install_key.arch(),
|
||||
native_arch,
|
||||
native_request
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if changelog.installed.len() == 1 {
|
||||
let installed = changelog.installed.iter().next().unwrap();
|
||||
// Ex) "Installed Python 3.9.7 in 1.68s"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue