diff --git a/src/build_options.rs b/src/build_options.rs index d05bfa2a7..06562b7b0 100644 --- a/src/build_options.rs +++ b/src/build_options.rs @@ -270,11 +270,10 @@ impl BuildOptions { let ext_suffix = sysconfig_data .get("EXT_SUFFIX") .context("syconfig didn't define an `EXT_SUFFIX` ಠ_ಠ")?; - let abi_tag = sysconfig_data - .get("SOABI") - .and_then(|abi| abi.split('-').nth(1).map(ToString::to_string)); - let interpreter_kind = sysconfig_data - .get("SOABI") + let soabi = sysconfig_data.get("SOABI"); + let abi_tag = + soabi.and_then(|abi| abi.split('-').nth(1).map(ToString::to_string)); + let interpreter_kind = soabi .and_then(|tag| { if tag.starts_with("pypy") { Some(InterpreterKind::PyPy) @@ -298,6 +297,8 @@ impl BuildOptions { executable: PathBuf::new(), platform: None, runnable: false, + implmentation_name: interpreter_kind.to_string().to_ascii_lowercase(), + soabi: soabi.cloned(), }); } else { if interpreter.is_empty() && !self.find_interpreter { @@ -376,6 +377,8 @@ impl BuildOptions { executable: PathBuf::new(), platform: None, runnable: false, + implmentation_name: "cpython".to_string(), + soabi: None, }]) } else if let Some(interp) = interpreters.get(0) { println!("🐍 Using {} to generate to link bindings (With abi3, an interpreter is only required on windows)", interp); @@ -396,6 +399,8 @@ impl BuildOptions { executable: PathBuf::new(), platform: None, runnable: false, + implmentation_name: "cpython".to_string(), + soabi: None, }]) } else { bail!("Failed to find a python interpreter"); @@ -438,6 +443,8 @@ impl BuildOptions { executable: PathBuf::new(), platform: None, runnable: false, + implmentation_name: "cpython".to_string(), + soabi: None, }]) } else if target.cross_compiling() { let mut interps = Vec::with_capacity(found_interpreters.len()); diff --git a/src/python_interpreter/get_interpreter_metadata.py b/src/python_interpreter/get_interpreter_metadata.py index 68f763aa3..7908cac36 100644 --- a/src/python_interpreter/get_interpreter_metadata.py +++ b/src/python_interpreter/get_interpreter_metadata.py @@ -20,12 +20,16 @@ ext_suffix = sysconfig.get_config_var("EXT_SUFFIX") metadata = { + # sys.implementation.name can differ from platform.python_implementation(), for example + # Pyston has sys.implementation.name == "pyston" while platform.python_implementation() == cpython + "implementation_name": sys.implementation.name, "executable": sys.executable or None, "major": sys.version_info.major, "minor": sys.version_info.minor, "abiflags": sysconfig.get_config_var("ABIFLAGS"), "interpreter": platform.python_implementation().lower(), "ext_suffix": ext_suffix, + "soabi": sysconfig.get_config_var("SOABI") or None, "abi_tag": (sysconfig.get_config_var("SOABI") or "-").split("-")[1] or None, "platform": sysconfig.get_platform(), # This one isn't technically necessary, but still very useful for sanity checks diff --git a/src/python_interpreter/mod.rs b/src/python_interpreter/mod.rs index 38f5a5202..9b413af76 100644 --- a/src/python_interpreter/mod.rs +++ b/src/python_interpreter/mod.rs @@ -318,6 +318,7 @@ impl FromStr for InterpreterKind { /// The output format of [GET_INTERPRETER_METADATA] #[derive(Deserialize)] struct InterpreterMetadataMessage { + implementation_name: String, executable: Option, major: usize, minor: usize, @@ -328,6 +329,7 @@ struct InterpreterMetadataMessage { platform: String, // comes from `platform.system()` system: String, + soabi: Option, abi_tag: Option, } @@ -350,6 +352,10 @@ pub struct PythonInterpreter { /// When cross compile the target interpreter isn't runnable, /// and it's `executable` is empty pub runnable: bool, + /// Comes from `sys.platform.name` + pub implmentation_name: String, + /// Comes from sysconfig var `SOABI` + pub soabi: Option, } impl Deref for PythonInterpreter { @@ -440,41 +446,58 @@ impl PythonInterpreter { } else { target.get_platform_tag(platform_tags, universal2)? }; - let tag = match self.interpreter_kind { - InterpreterKind::CPython => { - if target.is_unix() { - format!( - "cp{major}{minor}-cp{major}{minor}{abiflags}-{platform}", - major = self.major, - minor = self.minor, - abiflags = self.abiflags, - platform = platform - ) - } else { - // On windows the abiflags are missing, but this seems to work + let tag = if self.implmentation_name.parse::().is_err() { + // Use generic tags when `sys.implementation.name` != `platform.python_implementation()`, for example Pyston + // See also https://github.com/pypa/packaging/blob/0031046f7fad649580bc3127d1cef9157da0dd79/packaging/tags.py#L234-L261 + format!( + "{interpreter}{major}{minor}-{soabi}-{platform}", + interpreter = self.implmentation_name, + major = self.major, + minor = self.minor, + soabi = self + .soabi + .as_deref() + .unwrap_or("none") + .replace(['-', '.'], "_"), + platform = platform + ) + } else { + match self.interpreter_kind { + InterpreterKind::CPython => { + if target.is_unix() { + format!( + "cp{major}{minor}-cp{major}{minor}{abiflags}-{platform}", + major = self.major, + minor = self.minor, + abiflags = self.abiflags, + platform = platform + ) + } else { + // On windows the abiflags are missing, but this seems to work + format!( + "cp{major}{minor}-none-{platform}", + major = self.major, + minor = self.minor, + platform = platform + ) + } + } + InterpreterKind::PyPy => { + // pypy uses its version as part of the ABI, e.g. + // pypy 3.7 7.3 => numpy-1.20.1-pp37-pypy37_pp73-manylinux2014_x86_64.whl format!( - "cp{major}{minor}-none-{platform}", + "pp{major}{minor}-pypy{major}{minor}_{abi_tag}-{platform}", major = self.major, minor = self.minor, - platform = platform + // TODO: Proper tag handling for pypy + abi_tag = self + .abi_tag + .clone() + .expect("PyPy's syconfig didn't define an `SOABI` ಠ_ಠ"), + platform = platform, ) } } - InterpreterKind::PyPy => { - // pypy uses its version as part of the ABI, e.g. - // pypy 3.7 7.3 => numpy-1.20.1-pp37-pypy37_pp73-manylinux2014_x86_64.whl - format!( - "pp{major}{minor}-pypy{major}{minor}_{abi_tag}-{platform}", - major = self.major, - minor = self.minor, - // TODO: Proper tag handling for pypy - abi_tag = self - .abi_tag - .clone() - .expect("PyPy's syconfig didn't define an `SOABI` ಠ_ಠ"), - platform = platform, - ) - } }; Ok(tag) } @@ -598,13 +621,7 @@ impl PythonInterpreter { // We don't use platform from sysconfig on macOS None } else { - Some( - message - .platform - .to_lowercase() - .replace('-', "_") - .replace('.', "_"), - ) + Some(message.platform.to_lowercase().replace(['-', '.'], "_")) }; Ok(Some(PythonInterpreter { @@ -625,16 +642,21 @@ impl PythonInterpreter { .unwrap_or_else(|| executable.as_ref().to_path_buf()), platform, runnable: true, + implmentation_name: message.implementation_name, + soabi: message.soabi, })) } /// Construct a `PythonInterpreter` from a sysconfig and target pub fn from_config(config: InterpreterConfig) -> Self { + let implmentation_name = config.interpreter_kind.to_string().to_ascii_lowercase(); PythonInterpreter { config, executable: PathBuf::new(), platform: None, runnable: false, + implmentation_name, + soabi: None, } }