diff --git a/Cargo.toml b/Cargo.toml index 72a90713..270b9390 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,13 @@ rustversion = "1.0" [features] default = ["macros"] macros = ["ctor", "indoc", "inventory", "paste", "pyo3cls", "unindent"] -# Use the Python limited API. See https://www.python.org/dev/peps/pep-0384/ for -# more. +# Use the Python limited API. See https://www.python.org/dev/peps/pep-0384/ for more. abi3 = [] +# With abi3, we can manually set the minimum Python version. +abi3-py36 = ["abi3"] +abi3-py37 = ["abi3-py36"] +abi3-py38 = ["abi3-py37"] +abi3-py39 = ["abi3-py38"] # Optimizes PyObject to Vec conversion and so on. nightly = [] diff --git a/build.rs b/build.rs index 1d4d78f6..8b87fa2b 100644 --- a/build.rs +++ b/build.rs @@ -9,7 +9,10 @@ use std::{ str::FromStr, }; -const PY3_MIN_MINOR: u8 = 5; +/// Minimum required Python version. +const PY3_MIN_MINOR: u8 = 6; +/// Maximum Python version that can be used as minimum required Python version with abi3. +const ABI3_MAX_MINOR: u8 = 9; const CFG_KEY: &str = "py_sys_config"; type Result = std::result::Result>; @@ -770,12 +773,25 @@ fn configure(interpreter_config: &InterpreterConfig) -> Result { bail!("Python 2 is not supported"); } - if env::var_os("CARGO_FEATURE_ABI3").is_some() { + let minor = if env::var_os("CARGO_FEATURE_ABI3").is_some() { println!("cargo:rustc-cfg=Py_LIMITED_API"); - } + // Check any `abi3-py3*` feature is set. If not, use the interpreter version. + let abi3_minor = (PY3_MIN_MINOR..=ABI3_MAX_MINOR) + .find(|i| env::var_os(format!("CARGO_FEATURE_ABI3_PY3{}", i)).is_some()); + match (abi3_minor, interpreter_config.version.minor) { + (Some(abi3_minor), Some(interpreter_minor)) if abi3_minor > interpreter_minor => bail!( + "You cannot set a mininimum Python version {} higher than the interpreter version {}", + abi3_minor, + interpreter_minor + ), + _ => abi3_minor.or(interpreter_config.version.minor), + } + } else { + interpreter_config.version.minor + }; - if let Some(minor) = interpreter_config.version.minor { - for i in 6..=minor { + if let Some(minor) = minor { + for i in PY3_MIN_MINOR..=minor { println!("cargo:rustc-cfg=Py_3_{}", i); flags += format!("CFG_Py_3_{},", i).as_ref(); }