diff --git a/Changelog.md b/Changelog.md index 77ccd48e7..8b02442f6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ ## Unreleased +* Allow iOS cross-platform virtual environments, such as those used by cibuildwheel, to imply an iOS target. * Fix iOS wheel naming to be compliant with PEP 730. * Fix generated WHEEL Tag metadata to be spec compliant. * Remove `add_directory()` from ModuleWriter and make it an implementation detail for the specific impl diff --git a/src/build_options.rs b/src/build_options.rs index 4c03915c2..368c0af40 100644 --- a/src/build_options.rs +++ b/src/build_options.rs @@ -6,7 +6,9 @@ use crate::cross_compile::{find_sysconfigdata, parse_sysconfigdata}; use crate::project_layout::ProjectResolver; use crate::pyproject_toml::ToolMaturin; use crate::python_interpreter::{InterpreterConfig, InterpreterKind}; -use crate::target::{detect_arch_from_python, is_arch_supported_by_pypi}; +use crate::target::{ + detect_arch_from_python, detect_target_from_cross_python, is_arch_supported_by_pypi, +}; use crate::{BridgeModel, BuildContext, PyO3, PythonInterpreter, Target}; use anyhow::{bail, format_err, Context, Result}; use cargo_metadata::{CrateType, PackageId, TargetKind}; @@ -665,7 +667,22 @@ impl BuildContextBuilder { let mut target = Target::from_target_triple(target_triple.as_ref())?; if !target.user_specified && !universal2 { if let Some(interpreter) = build_options.interpreter.first() { - if let Some(detected_target) = detect_arch_from_python(interpreter, &target) { + // If there's an explicitly provided interpreter, check to see + // if it's a cross-compiling interpreter; otherwise, check to + // see if an target change is required. + if let Some(detected_target) = detect_target_from_cross_python(interpreter) { + target = Target::from_target_triple(Some(&detected_target))?; + } else if let Some(detected_target) = detect_arch_from_python(interpreter, &target) + { + target = Target::from_target_triple(Some(&detected_target))?; + } + } else { + // If there's no explicit user-provided target or interpreter, + // check the interpreter; if the interpreter identifies as a + // cross compiler, set the target based on the platform reported + // by the interpreter. + if let Some(detected_target) = detect_target_from_cross_python(&target.get_python()) + { target = Target::from_target_triple(Some(&detected_target))?; } } diff --git a/src/cross_compile.rs b/src/cross_compile.rs index 039a28eff..7bd8ed284 100644 --- a/src/cross_compile.rs +++ b/src/cross_compile.rs @@ -1,3 +1,4 @@ +use crate::target::Os; use crate::{PythonInterpreter, Target}; use anyhow::{bail, Result}; use fs_err::{self as fs, DirEntry}; @@ -32,6 +33,13 @@ pub fn is_cross_compiling(target: &Target) -> Result { return Ok(false); } + if target.target_os() == Os::Ios { + // Not cross-compiling to compile for iOS. There's no on-device compilation, + // so compilation will always be in a "fake" cross-platform venv with a + // working python/sysconfig that can interrogated. + return Ok(false); + } + Ok(true) } diff --git a/src/target/mod.rs b/src/target/mod.rs index 3aa3d5f31..7c6bff311 100644 --- a/src/target/mod.rs +++ b/src/target/mod.rs @@ -764,3 +764,24 @@ pub(crate) fn detect_arch_from_python(python: &PathBuf, target: &Target) -> Opti } None } + +pub(crate) fn detect_target_from_cross_python(python: &PathBuf) -> Option { + match Command::new(python) + .arg("-c") + .arg("import sys, sysconfig; print(sysconfig.get_platform(), end='') if getattr(sys, 'cross_compiling', False) else ''") + .output() + { + Ok(output) if output.status.success() => { + let platform = String::from_utf8_lossy(&output.stdout); + if platform.ends_with("-arm64-iphoneos") { + return Some(TargetTriple::Regular("aarch64-apple-ios".to_string())); + } else if platform.ends_with("-arm64-iphonesimulator") { + return Some(TargetTriple::Regular("aarch64-apple-ios-sim".to_string())); + } else if platform.ends_with("-x86_64-iphonesimulator") { + return Some(TargetTriple::Regular("x86_64-apple-ios".to_string())); + } + } + _ => eprintln!("⚠️ Warning: Failed to determine python platform"), + } + None +}