Skip to content

Commit e31b8db

Browse files
committed
Fallback to sysconfig interpreters for pyo3 bindings
1 parent 9951364 commit e31b8db

File tree

3 files changed

+70
-29
lines changed

3 files changed

+70
-29
lines changed

Changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
* Add support for packaging multiple pure Python packages in [#1378](https://github.com/PyO3/maturin/pull/1378)
11+
* Fallback to sysconfig interpreters for pyo3 bindings in [#1381](https://github.com/PyO3/maturin/pull/1381)
1112

1213
## [0.14.7] - 2022-12-20
1314

src/build_options.rs

+54-25
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::collections::{HashMap, HashSet};
1313
use std::env;
1414
use std::ops::{Deref, DerefMut};
1515
use std::path::PathBuf;
16+
use tracing::debug;
1617

1718
// This is used for BridgeModel::Bindings("pyo3-ffi") and BridgeModel::Bindings("pyo3").
1819
// These should be treated almost identically but must be correctly identified
@@ -218,7 +219,6 @@ impl BuildOptions {
218219
) -> Result<Vec<PythonInterpreter>> {
219220
match bridge {
220221
BridgeModel::Bindings(binding_name, _) | BridgeModel::Bin(Some((binding_name, _))) => {
221-
let mut native_interpreters = false;
222222
let mut interpreters = Vec::new();
223223
if let Some(config_file) = env::var_os("PYO3_CONFIG_FILE") {
224224
if !binding_name.starts_with("pyo3") {
@@ -307,37 +307,20 @@ impl BuildOptions {
307307
interpreters =
308308
find_interpreter_in_sysconfig(interpreter, target, min_python_minor)?;
309309
}
310+
} else if binding_name.starts_with("pyo3") {
311+
// Only pyo3/pyo3-ffi bindings supports bundled sysconfig interpreters
312+
interpreters = find_interpreter(bridge, interpreter, target, min_python_minor)?;
310313
} else {
311-
match find_interpreter_in_host(bridge, interpreter, target, min_python_minor) {
312-
Ok(host_interps) => {
313-
interpreters = host_interps;
314-
native_interpreters = true;
315-
}
316-
Err(err) => {
317-
if binding_name.starts_with("pyo3") && target.is_unix() {
318-
interpreters = find_interpreter_in_sysconfig(
319-
interpreter,
320-
target,
321-
min_python_minor,
322-
)
323-
.map_err(|_| err)?;
324-
} else {
325-
return Err(err);
326-
}
327-
}
328-
}
314+
interpreters =
315+
find_interpreter_in_host(bridge, interpreter, target, min_python_minor)?;
329316
}
330317

331318
let interpreters_str = interpreters
332319
.iter()
333320
.map(ToString::to_string)
334321
.collect::<Vec<String>>()
335322
.join(", ");
336-
if native_interpreters {
337-
println!("🐍 Found {}", interpreters_str);
338-
} else {
339-
println!("🐍 Found cross compiling target {}", interpreters_str);
340-
}
323+
println!("🐍 Found {}", interpreters_str);
341324

342325
Ok(interpreters)
343326
}
@@ -994,6 +977,43 @@ fn find_single_python_interpreter(
994977
Ok(interpreter)
995978
}
996979

980+
/// Find python interpreters in host machine first,
981+
/// fallback to bundled sysconfig if not found in host machine
982+
fn find_interpreter(
983+
bridge: &BridgeModel,
984+
interpreter: &[PathBuf],
985+
target: &Target,
986+
min_python_minor: Option<usize>,
987+
) -> Result<Vec<PythonInterpreter>> {
988+
let mut interpreters = Vec::new();
989+
if !interpreter.is_empty() {
990+
let mut missing = Vec::new();
991+
for interp in interpreter {
992+
match PythonInterpreter::check_executable(interp.clone(), target, bridge) {
993+
Ok(Some(interp)) => interpreters.push(interp),
994+
_ => missing.push(interp.clone()),
995+
}
996+
}
997+
if !missing.is_empty() {
998+
let sysconfig_interps =
999+
find_interpreter_in_sysconfig(&missing, target, min_python_minor)?;
1000+
interpreters.extend(sysconfig_interps);
1001+
}
1002+
} else {
1003+
interpreters = PythonInterpreter::find_all(target, bridge, min_python_minor)
1004+
.context("Finding python interpreters failed")?;
1005+
};
1006+
1007+
if interpreters.is_empty() {
1008+
if let Some(minor) = min_python_minor {
1009+
bail!("Couldn't find any python interpreters with version >= 3.{}. Please specify at least one with -i", minor);
1010+
} else {
1011+
bail!("Couldn't find any python interpreters. Please specify at least one with -i");
1012+
}
1013+
}
1014+
Ok(interpreters)
1015+
}
1016+
9971017
/// Find python interpreters in the host machine
9981018
fn find_interpreter_in_host(
9991019
bridge: &BridgeModel,
@@ -1070,7 +1090,16 @@ fn find_interpreter_in_sysconfig(
10701090
python_impl,
10711091
(ver_major, ver_minor),
10721092
)
1073-
.context("Failed to find a python interpreter")?;
1093+
.with_context(|| {
1094+
format!(
1095+
"Failed to find a {} {}.{} interpreter",
1096+
python_impl, ver_major, ver_minor
1097+
)
1098+
})?;
1099+
debug!(
1100+
"Found {} {}.{} in bundled sysconfig",
1101+
sysconfig.interpreter_kind, sysconfig.major, sysconfig.minor,
1102+
);
10741103
interpreters.push(PythonInterpreter::from_config(sysconfig.clone()));
10751104
}
10761105
Ok(interpreters)

src/python_interpreter/mod.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::ops::Deref;
1111
use std::path::{Path, PathBuf};
1212
use std::process::{Command, Stdio};
1313
use std::str::{self, FromStr};
14+
use tracing::debug;
1415

1516
mod config;
1617

@@ -613,6 +614,10 @@ impl PythonInterpreter {
613614
.context(String::from_utf8_lossy(&output.stdout).trim().to_string())?;
614615

615616
if (message.major == 2 && message.minor != 7) || (message.major == 3 && message.minor < 5) {
617+
debug!(
618+
"Skipping outdated python interpreter '{}'",
619+
executable.as_ref().display()
620+
);
616621
return Ok(None);
617622
}
618623

@@ -636,6 +641,15 @@ impl PythonInterpreter {
636641
Some(message.platform.to_lowercase().replace(['-', '.'], "_"))
637642
};
638643

644+
let executable = message
645+
.executable
646+
.map(PathBuf::from)
647+
.unwrap_or_else(|| executable.as_ref().to_path_buf());
648+
debug!(
649+
"Found {} interpreter at {}",
650+
interpreter,
651+
executable.display()
652+
);
639653
Ok(Some(PythonInterpreter {
640654
config: InterpreterConfig {
641655
major: message.major,
@@ -648,10 +662,7 @@ impl PythonInterpreter {
648662
abi_tag: message.abi_tag,
649663
pointer_width: None,
650664
},
651-
executable: message
652-
.executable
653-
.map(PathBuf::from)
654-
.unwrap_or_else(|| executable.as_ref().to_path_buf()),
665+
executable,
655666
platform,
656667
runnable: true,
657668
implmentation_name: message.implementation_name,

0 commit comments

Comments
 (0)