diff --git a/Cargo.lock b/Cargo.lock index 71363faa0c41..0c738773dec1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2475,6 +2475,30 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "procfs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +dependencies = [ + "bitflags 2.6.0", + "flate2", + "hex", + "lazy_static", + "procfs-core", + "rustix", +] + +[[package]] +name = "procfs-core" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +dependencies = [ + "bitflags 2.6.0", + "hex", +] + [[package]] name = "ptr_meta" version = "0.3.0" @@ -5002,6 +5026,7 @@ dependencies = [ "indoc", "itertools 0.13.0", "owo-colors", + "procfs", "regex", "reqwest", "reqwest-middleware", diff --git a/Cargo.toml b/Cargo.toml index e02a6ae63def..997df02e91c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,6 +125,7 @@ path-slash = { version = "0.2.1" } pathdiff = { version = "0.2.1" } petgraph = { version = "0.6.5" } platform-info = { version = "2.0.3" } +procfs = { version = "0.16.0" , default-features = false, features = ["flate2"] } proc-macro2 = { version = "1.0.86" } pubgrub = { git = "https://github.com/astral-sh/pubgrub", rev = "95e1390399cdddee986b658be19587eb1fdb2d79" } version-ranges = { git = "https://github.com/astral-sh/pubgrub", rev = "95e1390399cdddee986b658be19587eb1fdb2d79" } diff --git a/crates/uv-python/Cargo.toml b/crates/uv-python/Cargo.toml index 361d3fa7da68..7dbb92d13a8c 100644 --- a/crates/uv-python/Cargo.toml +++ b/crates/uv-python/Cargo.toml @@ -57,6 +57,9 @@ tracing = { workspace = true } url = { workspace = true } which = { workspace = true } +[target.'cfg(target_os = "linux")'.dependencies] +procfs = { workspace = true } + [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { workspace = true } windows-registry = { workspace = true } diff --git a/crates/uv-python/src/cpuinfo.rs b/crates/uv-python/src/cpuinfo.rs new file mode 100644 index 000000000000..f0827886be74 --- /dev/null +++ b/crates/uv-python/src/cpuinfo.rs @@ -0,0 +1,33 @@ +//! Fetches CPU information. + +use anyhow::Error; + +#[cfg(target_os = "linux")] +use procfs::{CpuInfo, Current}; + +/// Detects whether the hardware supports floating-point operations using ARM's Vector Floating Point (VFP) hardware. +/// +/// This function is relevant specifically for ARM architectures, where the presence of the "vfp" flag in `/proc/cpuinfo` +/// indicates that the CPU supports hardware floating-point operations. +/// This helps determine whether the system is using the `gnueabihf` (hard-float) ABI or `gnueabi` (soft-float) ABI. +/// +/// More information on this can be found in the [Debian ARM Hard Float Port documentation](https://wiki.debian.org/ArmHardFloatPort#VFP). +#[cfg(target_os = "linux")] +pub(crate) fn detect_hardware_floating_point_support() -> Result { + let cpu_info = CpuInfo::current()?; + if let Some(features) = cpu_info.fields.get("Features") { + if features.contains("vfp") { + return Ok(true); // "vfp" found: hard-float (gnueabihf) detected + } + } + + Ok(false) // Default to soft-float (gnueabi) if no "vfp" flag is found +} + +/// For non-Linux systems or architectures, the function will return `false` as hardware floating-point detection +/// is not applicable outside of Linux ARM architectures. +#[cfg(not(target_os = "linux"))] +#[allow(clippy::unnecessary_wraps)] +pub(crate) fn detect_hardware_floating_point_support() -> Result { + Ok(false) // Non-Linux or non-ARM systems: hardware floating-point detection is not applicable +} diff --git a/crates/uv-python/src/lib.rs b/crates/uv-python/src/lib.rs index 3cad5989c13b..c12ce93ad487 100644 --- a/crates/uv-python/src/lib.rs +++ b/crates/uv-python/src/lib.rs @@ -21,6 +21,7 @@ pub use crate::version_files::{ }; pub use crate::virtualenv::{Error as VirtualEnvError, PyVenvConfiguration, VirtualEnvironment}; +mod cpuinfo; mod discovery; pub mod downloads; mod environment; diff --git a/crates/uv-python/src/platform.rs b/crates/uv-python/src/platform.rs index b15d102701db..6b54477c0467 100644 --- a/crates/uv-python/src/platform.rs +++ b/crates/uv-python/src/platform.rs @@ -1,3 +1,4 @@ +use crate::cpuinfo::detect_hardware_floating_point_support; use crate::libc::{detect_linux_libc, LibcDetectionError, LibcVersion}; use std::fmt::Display; use std::ops::Deref; @@ -30,7 +31,17 @@ impl Libc { pub(crate) fn from_env() -> Result { match std::env::consts::OS { "linux" => Ok(Self::Some(match detect_linux_libc()? { - LibcVersion::Manylinux { .. } => target_lexicon::Environment::Gnu, + LibcVersion::Manylinux { .. } => match std::env::consts::ARCH { + // Checks if the CPU supports hardware floating-point operations. + // Depending on the result, it selects either the `gnueabihf` (hard-float) or `gnueabi` (soft-float) environment. + // download-metadata.json only includes armv7. + "arm" | "armv7" => match detect_hardware_floating_point_support() { + Ok(true) => target_lexicon::Environment::Gnueabihf, + Ok(false) => target_lexicon::Environment::Gnueabi, + Err(_) => target_lexicon::Environment::Gnu, + }, + _ => target_lexicon::Environment::Gnu, + }, LibcVersion::Musllinux { .. } => target_lexicon::Environment::Musl, })), "windows" | "macos" => Ok(Self::None),