Merge pull request #1469 from PyO3/deny-pypy-and-abi3

Show warning when abi3 is used with PyPy
This commit is contained in:
David Hewitt 2021-03-06 23:09:38 +00:00 committed by GitHub
commit 4c80ce93c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 45 additions and 27 deletions

View File

@ -23,6 +23,13 @@ macro_rules! bail {
($fmt: literal $(, $args: expr)+) => { return Err(format!($fmt $(,$args)+).into()); }; ($fmt: literal $(, $args: expr)+) => { return Err(format!($fmt $(,$args)+).into()); };
} }
// Show warning. If needed, please extend this macro to support arguments.
macro_rules! warn {
($msg: literal) => {
println!(concat!("cargo:warning=", $msg));
};
}
/// Information returned from python interpreter /// Information returned from python interpreter
#[derive(Debug)] #[derive(Debug)]
struct InterpreterConfig { struct InterpreterConfig {
@ -34,13 +41,23 @@ struct InterpreterConfig {
base_prefix: String, base_prefix: String,
executable: PathBuf, executable: PathBuf,
calcsize_pointer: Option<u32>, calcsize_pointer: Option<u32>,
implementation: PythonInterpreterKind,
} }
#[derive(Debug, Clone)] impl InterpreterConfig {
fn is_pypy(&self) -> bool {
self.implementation == PythonInterpreterKind::PyPy
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
struct PythonVersion { struct PythonVersion {
major: u8, major: u8,
minor: u8, minor: u8,
implementation: PythonInterpreterKind, }
impl PythonVersion {
const PY37: Self = PythonVersion { major: 3, minor: 7 };
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -60,6 +77,10 @@ impl FromStr for PythonInterpreterKind {
} }
} }
fn is_abi3() -> bool {
env::var_os("CARGO_FEATURE_ABI3").is_some()
}
trait GetPrimitive { trait GetPrimitive {
fn get_bool(&self, key: &str) -> Result<bool>; fn get_bool(&self, key: &str) -> Result<bool>;
fn get_numeric<T: FromStr>(&self, key: &str) -> Result<T>; fn get_numeric<T: FromStr>(&self, key: &str) -> Result<T>;
@ -266,16 +287,14 @@ impl BuildFlags {
fn fixup(&mut self, interpreter_config: &InterpreterConfig) { fn fixup(&mut self, interpreter_config: &InterpreterConfig) {
if self.0.contains("Py_DEBUG") { if self.0.contains("Py_DEBUG") {
self.0.insert("Py_REF_DEBUG"); self.0.insert("Py_REF_DEBUG");
if interpreter_config.version.major == 3 && interpreter_config.version.minor <= 7 { if interpreter_config.version <= PythonVersion::PY37 {
// Py_DEBUG only implies Py_TRACE_REFS until Python 3.7 // Py_DEBUG only implies Py_TRACE_REFS until Python 3.7
self.0.insert("Py_TRACE_REFS"); self.0.insert("Py_TRACE_REFS");
} }
} }
// WITH_THREAD is always on for Python 3.7, and for PyPy. // WITH_THREAD is always on for Python 3.7, and for PyPy.
if (interpreter_config.version.implementation == PythonInterpreterKind::PyPy) if interpreter_config.is_pypy() || interpreter_config.version >= PythonVersion::PY37 {
|| (interpreter_config.version.major == 3 && interpreter_config.version.minor >= 7)
{
self.0.insert("WITH_THREAD"); self.0.insert("WITH_THREAD");
} }
} }
@ -455,11 +474,7 @@ fn load_cross_compile_from_sysconfigdata(
}; };
let calcsize_pointer = sysconfig_data.get_numeric("SIZEOF_VOID_P").ok(); let calcsize_pointer = sysconfig_data.get_numeric("SIZEOF_VOID_P").ok();
let python_version = PythonVersion { let python_version = PythonVersion { major, minor };
major,
minor,
implementation: PythonInterpreterKind::CPython,
};
let interpreter_config = InterpreterConfig { let interpreter_config = InterpreterConfig {
version: python_version, version: python_version,
@ -469,6 +484,7 @@ fn load_cross_compile_from_sysconfigdata(
base_prefix: "".to_string(), base_prefix: "".to_string(),
executable: PathBuf::new(), executable: PathBuf::new(),
calcsize_pointer, calcsize_pointer,
implementation: PythonInterpreterKind::CPython,
}; };
let build_flags = BuildFlags::from_config_map(&sysconfig_data); let build_flags = BuildFlags::from_config_map(&sysconfig_data);
@ -486,11 +502,7 @@ fn load_cross_compile_from_headers(
let major = patchlevel_defines.get_numeric("PY_MAJOR_VERSION")?; let major = patchlevel_defines.get_numeric("PY_MAJOR_VERSION")?;
let minor = patchlevel_defines.get_numeric("PY_MINOR_VERSION")?; let minor = patchlevel_defines.get_numeric("PY_MINOR_VERSION")?;
let python_version = PythonVersion { let python_version = PythonVersion { major, minor };
major,
minor,
implementation: PythonInterpreterKind::CPython,
};
let config_data = parse_header_defines(python_include_dir.join("pyconfig.h"))?; let config_data = parse_header_defines(python_include_dir.join("pyconfig.h"))?;
@ -502,6 +514,7 @@ fn load_cross_compile_from_headers(
base_prefix: "".to_string(), base_prefix: "".to_string(),
executable: PathBuf::new(), executable: PathBuf::new(),
calcsize_pointer: None, calcsize_pointer: None,
implementation: PythonInterpreterKind::CPython,
}; };
let build_flags = BuildFlags::from_config_map(&config_data); let build_flags = BuildFlags::from_config_map(&config_data);
@ -531,11 +544,7 @@ fn windows_hardcoded_cross_compile(
bail!("One of PYO3_CROSS_INCLUDE_DIR, PYO3_CROSS_PYTHON_VERSION, or an abi3-py3* feature must be specified when cross-compiling for Windows.") bail!("One of PYO3_CROSS_INCLUDE_DIR, PYO3_CROSS_PYTHON_VERSION, or an abi3-py3* feature must be specified when cross-compiling for Windows.")
}; };
let python_version = PythonVersion { let python_version = PythonVersion { major, minor };
major,
minor,
implementation: PythonInterpreterKind::CPython,
};
let interpreter_config = InterpreterConfig { let interpreter_config = InterpreterConfig {
version: python_version, version: python_version,
@ -545,6 +554,7 @@ fn windows_hardcoded_cross_compile(
base_prefix: "".to_string(), base_prefix: "".to_string(),
executable: PathBuf::new(), executable: PathBuf::new(),
calcsize_pointer: None, calcsize_pointer: None,
implementation: PythonInterpreterKind::CPython,
}; };
Ok((interpreter_config, BuildFlags::windows_hardcoded())) Ok((interpreter_config, BuildFlags::windows_hardcoded()))
@ -609,6 +619,7 @@ fn get_rustc_link_lib(config: &InterpreterConfig) -> String {
let link_name = if env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() == "windows" { let link_name = if env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() == "windows" {
if env::var("CARGO_CFG_TARGET_ENV").unwrap().as_str() == "gnu" { if env::var("CARGO_CFG_TARGET_ENV").unwrap().as_str() == "gnu" {
// https://packages.msys2.org/base/mingw-w64-python // https://packages.msys2.org/base/mingw-w64-python
// TODO: ABI3?
format!( format!(
"pythonXY:python{}.{}", "pythonXY:python{}.{}",
config.version.major, config.version.minor config.version.major, config.version.minor
@ -618,7 +629,7 @@ fn get_rustc_link_lib(config: &InterpreterConfig) -> String {
// See https://www.python.org/dev/peps/pep-0384/#linkage // See https://www.python.org/dev/peps/pep-0384/#linkage
// //
// This contains only the limited ABI symbols. // This contains only the limited ABI symbols.
if env::var_os("CARGO_FEATURE_ABI3").is_some() { if is_abi3() {
"pythonXY:python3".to_owned() "pythonXY:python3".to_owned()
} else { } else {
format!( format!(
@ -628,7 +639,7 @@ fn get_rustc_link_lib(config: &InterpreterConfig) -> String {
} }
} }
} else { } else {
match config.version.implementation { match config.implementation {
PythonInterpreterKind::CPython => format!("python{}", config.ld_version), PythonInterpreterKind::CPython => format!("python{}", config.ld_version),
PythonInterpreterKind::PyPy => format!("pypy{}-c", config.version.major), PythonInterpreterKind::PyPy => format!("pypy{}-c", config.version.major),
} }
@ -736,8 +747,8 @@ print("calcsize_pointer", struct.calcsize("P"))
version: PythonVersion { version: PythonVersion {
major: map["version_major"].parse()?, major: map["version_major"].parse()?,
minor: map["version_minor"].parse()?, minor: map["version_minor"].parse()?,
implementation: map["implementation"].parse()?,
}, },
implementation: map["implementation"].parse()?,
libdir: map.get("libdir").cloned(), libdir: map.get("libdir").cloned(),
shared, shared,
ld_version: map["ld_version"].clone(), ld_version: map["ld_version"].clone(),
@ -781,14 +792,21 @@ fn configure(interpreter_config: &InterpreterConfig) -> Result<()> {
println!("cargo:rustc-cfg=Py_SHARED"); println!("cargo:rustc-cfg=Py_SHARED");
} }
if interpreter_config.version.implementation == PythonInterpreterKind::PyPy { let is_abi3 = is_abi3();
if interpreter_config.is_pypy() {
println!("cargo:rustc-cfg=PyPy"); println!("cargo:rustc-cfg=PyPy");
if is_abi3 {
warn!(
"PyPy does not yet support abi3 so the resulting wheel will be version-specific. \
See https://foss.heptapod.net/pypy/pypy/-/issues/3397 for more information."
)
}
}; };
let minor = if env::var_os("CARGO_FEATURE_ABI3").is_some() { let minor = if is_abi3 {
println!("cargo:rustc-cfg=Py_LIMITED_API"); println!("cargo:rustc-cfg=Py_LIMITED_API");
// Check any `abi3-py3*` feature is set. If not, use the interpreter version. // Check any `abi3-py3*` feature is set. If not, use the interpreter version.
match get_abi3_minor_version() { match get_abi3_minor_version() {
Some(minor) if minor > interpreter_config.version.minor => bail!( Some(minor) if minor > interpreter_config.version.minor => bail!(
"You cannot set a mininimum Python version 3.{} higher than the interpreter version 3.{}", "You cannot set a mininimum Python version 3.{} higher than the interpreter version 3.{}",