diff --git a/src/build_options.rs b/src/build_options.rs index 565e7bbcd..305531ccf 100644 --- a/src/build_options.rs +++ b/src/build_options.rs @@ -17,6 +17,12 @@ use std::env; use std::io; use std::path::PathBuf; +// This is used for BridgeModel::Bindings("pyo3-ffi") and BridgeModel::Bindings("pyo3"). +// These should be treated almost identically but must be correctly identified +// as one or the other in logs. pyo3-ffi is ordered first because it is newer +// and more restrictive. +const PYO3_BINDING_CRATES: [&str; 2] = ["pyo3-ffi", "pyo3"]; + /// High level API for building wheels from a crate which is also used for the CLI #[derive(Debug, Serialize, Deserialize, clap::Parser, Clone, Eq, PartialEq)] #[serde(default)] @@ -382,44 +388,44 @@ fn has_abi3(cargo_metadata: &Metadata) -> Result> { .resolve .as_ref() .context("Expected cargo to return metadata with resolve")?; - let pyo3_packages = resolve - .nodes - .iter() - .filter(|package| cargo_metadata[&package.id].name == "pyo3") - .collect::>(); - match pyo3_packages.as_slice() { - [pyo3_crate] => { - // Find the minimal abi3 python version. If there is none, abi3 hasn't been selected - // This parser abi3-py{major}{minor} and returns the minimal (major, minor) tuple - let abi3_selected = pyo3_crate.features.iter().any(|x| x == "abi3"); - - let min_abi3_version = pyo3_crate - .features - .iter() - .filter(|x| x.starts_with("abi3-py") && x.len() >= "abi3-pyxx".len()) - .map(|x| { - Ok(( - (x.as_bytes()[7] as char).to_string().parse::()?, - x[8..].parse::()?, - )) - }) - .collect::>>() - .context("Bogus pyo3 cargo features")? - .into_iter() - .min(); - if abi3_selected && min_abi3_version.is_none() { - bail!( - "You have selected the `abi3` feature but not a minimum version (e.g. the `abi3-py36` feature). \ - maturin needs a minimum version feature to build abi3 wheels." - ) + for &lib in PYO3_BINDING_CRATES.iter() { + let pyo3_packages = resolve + .nodes + .iter() + .filter(|package| cargo_metadata[&package.id].name.as_str() == lib) + .collect::>(); + match pyo3_packages.as_slice() { + [pyo3_crate] => { + // Find the minimal abi3 python version. If there is none, abi3 hasn't been selected + // This parser abi3-py{major}{minor} and returns the minimal (major, minor) tuple + let abi3_selected = pyo3_crate.features.iter().any(|x| x == "abi3"); + + let min_abi3_version = pyo3_crate + .features + .iter() + .filter(|x| x.starts_with("abi3-py") && x.len() >= "abi3-pyxx".len()) + .map(|x| { + Ok(( + (x.as_bytes()[7] as char).to_string().parse::()?, + x[8..].parse::()?, + )) + }) + .collect::>>() + .context(format!("Bogus {} cargo features", lib))? + .into_iter() + .min(); + if abi3_selected && min_abi3_version.is_none() { + bail!( + "You have selected the `abi3` feature but not a minimum version (e.g. the `abi3-py36` feature). \ + maturin needs a minimum version feature to build abi3 wheels." + ) + } + return Ok(min_abi3_version); } - Ok(min_abi3_version) + _ => continue, } - _ => bail!(format!( - "Expected exactly one pyo3 dependency, found {}", - pyo3_packages.len() - )), } + Ok(None) } /// Tries to determine the [BridgeModel] for the target crate @@ -451,6 +457,8 @@ pub fn find_bridge(cargo_metadata: &Metadata, bridge: Option<&str>) -> Result
) -> Result