diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 718a11559..ca55f8cc6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -107,6 +107,12 @@ jobs: cargo run -- build --no-sdist -i python -m test-crates/pyo3-pure/Cargo.toml --target aarch64-apple-darwin --zig # Check wheels with twine twine check --strict test-crates/pyo3-pure/target/wheels/*.whl + - name: test cross compiling windows abi3 wheel + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get install -y mingw-w64 + rustup target add x86_64-pc-windows-gnu + cargo run -- build --no-sdist -m test-crates/pyo3-pure/Cargo.toml --target x86_64-pc-windows-gnu test-alpine: name: Test Alpine Linux diff --git a/src/build_options.rs b/src/build_options.rs index 9d035bca8..e057dd874 100644 --- a/src/build_options.rs +++ b/src/build_options.rs @@ -272,12 +272,25 @@ impl BuildOptions { None => PathBuf::from(&cargo_metadata.target_directory).join("wheels"), }; + let generate_abi3_import_lib = has_generate_abi3_import_lib(&cargo_metadata)?; let interpreter = if self.interpreter.is_empty() { // Auto-detect interpreters - find_interpreter(&bridge, &[], &target, get_min_python_minor(&metadata21))? + find_interpreter( + &bridge, + &[], + &target, + get_min_python_minor(&metadata21), + generate_abi3_import_lib, + )? } else { // User given list of interpreters - find_interpreter(&bridge, &self.interpreter, &target, None)? + find_interpreter( + &bridge, + &self.interpreter, + &target, + None, + generate_abi3_import_lib, + )? }; let mut rustc_extra_args = self.rustc_extra_args.clone(); @@ -450,6 +463,33 @@ fn has_abi3(cargo_metadata: &Metadata) -> Result> { Ok(None) } +/// pyo3 0.16.4+ supports building abi3 wheels without a working Python interpreter for Windows +/// when `generate-abi3-import-lib` feature is enabled +fn has_generate_abi3_import_lib(cargo_metadata: &Metadata) -> Result { + let resolve = cargo_metadata + .resolve + .as_ref() + .context("Expected cargo to return metadata with resolve")?; + 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] => { + let generate_import_lib = pyo3_crate + .features + .iter() + .any(|x| x == "generate-abi3-import-lib"); + return Ok(generate_import_lib); + } + _ => continue, + } + } + Ok(false) +} + /// Tries to determine the [BridgeModel] for the target crate pub fn find_bridge(cargo_metadata: &Metadata, bridge: Option<&str>) -> Result { let resolve = cargo_metadata @@ -505,7 +545,9 @@ pub fn find_bridge(cargo_metadata: &Metadata, bridge: Option<&str>) -> Result
= package .targets .iter() @@ -585,6 +627,7 @@ pub fn find_interpreter( interpreter: &[PathBuf], target: &Target, min_python_minor: Option, + generate_abi3_import_lib: bool, ) -> Result> { match bridge { BridgeModel::Bindings(binding_name, _) => { @@ -718,6 +761,9 @@ pub fn find_interpreter( platform: None, runnable: false, }]) + } else if generate_abi3_import_lib { + println!("🐍 Not using a specific python interpreter (Automatically generating windows import library)"); + Ok(Vec::new()) } else { let interp = interpreter .get(0) @@ -726,7 +772,7 @@ pub fn find_interpreter( Ok(interpreter) } } else { - println!("🐍 Not using a specific python interpreter (With abi3, an interpreter is only required on windows)"); + println!("🐍 Not using a specific python interpreter"); Ok(interpreter) } } diff --git a/test-crates/pyo3-pure/Cargo.toml b/test-crates/pyo3-pure/Cargo.toml index 4de0aa750..5eedffd77 100644 --- a/test-crates/pyo3-pure/Cargo.toml +++ b/test-crates/pyo3-pure/Cargo.toml @@ -7,7 +7,7 @@ description = "Implements a dummy function (get_fortytwo.DummyClass.get_42()) in license = "MIT" [dependencies] -pyo3 = { version = "0.16.4", features = ["abi3-py37", "extension-module"] } +pyo3 = { version = "0.16.4", features = ["abi3-py37", "extension-module", "generate-abi3-import-lib"] } [lib] name = "pyo3_pure"