pyo3-build-config: Create per-target cross config files
Rename `$OUT_DIR/pyo3-cross-compile-config.txt` to `$OUT_DIR/<triple>/pyo3-build-config.txt` to exclude the possibility of using stale build configuration data when the build target changes. Use the presence of the corresponding build configuration file in the `pyo3-build-config` build script output directory to detect whether we are cross compiling or not. This patch enables cross compilation without using any of `PYO3_CROSS_*` env variables in many cases.
This commit is contained in:
parent
328e7d69f6
commit
ccda497e04
|
@ -759,7 +759,7 @@ pub(crate) struct CrossCompileEnvVars {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrossCompileEnvVars {
|
impl CrossCompileEnvVars {
|
||||||
pub fn any(&self) -> bool {
|
fn any(&self) -> bool {
|
||||||
self.pyo3_cross.is_some()
|
self.pyo3_cross.is_some()
|
||||||
|| self.pyo3_cross_lib_dir.is_some()
|
|| self.pyo3_cross_lib_dir.is_some()
|
||||||
|| self.pyo3_cross_python_version.is_some()
|
|| self.pyo3_cross_python_version.is_some()
|
||||||
|
|
|
@ -11,7 +11,11 @@ mod errors;
|
||||||
mod impl_;
|
mod impl_;
|
||||||
|
|
||||||
#[cfg(feature = "resolve-config")]
|
#[cfg(feature = "resolve-config")]
|
||||||
use std::io::Cursor;
|
use std::{
|
||||||
|
io::Cursor,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
use std::{env, process::Command};
|
use std::{env, process::Command};
|
||||||
|
|
||||||
#[cfg(feature = "resolve-config")]
|
#[cfg(feature = "resolve-config")]
|
||||||
|
@ -69,14 +73,21 @@ fn _add_extension_module_link_args(target_os: &str, mut writer: impl std::io::Wr
|
||||||
pub fn get() -> &'static InterpreterConfig {
|
pub fn get() -> &'static InterpreterConfig {
|
||||||
static CONFIG: OnceCell<InterpreterConfig> = OnceCell::new();
|
static CONFIG: OnceCell<InterpreterConfig> = OnceCell::new();
|
||||||
CONFIG.get_or_init(|| {
|
CONFIG.get_or_init(|| {
|
||||||
|
// Check if we are in a build script and cross compiling to a different target.
|
||||||
|
let cross_compile_config_path = resolve_cross_compile_config_path();
|
||||||
|
let cross_compiling = cross_compile_config_path
|
||||||
|
.as_ref()
|
||||||
|
.map(|path| path.exists())
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
if let Some(interpreter_config) = InterpreterConfig::from_cargo_dep_env() {
|
if let Some(interpreter_config) = InterpreterConfig::from_cargo_dep_env() {
|
||||||
interpreter_config
|
interpreter_config
|
||||||
} else if !CONFIG_FILE.is_empty() {
|
} else if !CONFIG_FILE.is_empty() {
|
||||||
InterpreterConfig::from_reader(Cursor::new(CONFIG_FILE))
|
InterpreterConfig::from_reader(Cursor::new(CONFIG_FILE))
|
||||||
} else if !ABI3_CONFIG.is_empty() {
|
} else if !ABI3_CONFIG.is_empty() {
|
||||||
Ok(abi3_config())
|
Ok(abi3_config())
|
||||||
} else if impl_::cross_compile_env_vars().any() {
|
} else if cross_compiling {
|
||||||
InterpreterConfig::from_path(DEFAULT_CROSS_COMPILE_CONFIG_PATH)
|
InterpreterConfig::from_path(cross_compile_config_path.as_ref().unwrap())
|
||||||
} else {
|
} else {
|
||||||
InterpreterConfig::from_reader(Cursor::new(HOST_CONFIG))
|
InterpreterConfig::from_reader(Cursor::new(HOST_CONFIG))
|
||||||
}
|
}
|
||||||
|
@ -84,12 +95,6 @@ pub fn get() -> &'static InterpreterConfig {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Path where PyO3's build.rs will write configuration by default.
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[cfg(feature = "resolve-config")]
|
|
||||||
const DEFAULT_CROSS_COMPILE_CONFIG_PATH: &str =
|
|
||||||
concat!(env!("OUT_DIR"), "/pyo3-cross-compile-config.txt");
|
|
||||||
|
|
||||||
/// Build configuration provided by `PYO3_CONFIG_FILE`. May be empty if env var not set.
|
/// Build configuration provided by `PYO3_CONFIG_FILE`. May be empty if env var not set.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[cfg(feature = "resolve-config")]
|
#[cfg(feature = "resolve-config")]
|
||||||
|
@ -107,6 +112,22 @@ const ABI3_CONFIG: &str = include_str!(concat!(env!("OUT_DIR"), "/pyo3-build-con
|
||||||
#[cfg(feature = "resolve-config")]
|
#[cfg(feature = "resolve-config")]
|
||||||
const HOST_CONFIG: &str = include_str!(concat!(env!("OUT_DIR"), "/pyo3-build-config.txt"));
|
const HOST_CONFIG: &str = include_str!(concat!(env!("OUT_DIR"), "/pyo3-build-config.txt"));
|
||||||
|
|
||||||
|
/// Returns the path where PyO3's build.rs writes its cross compile configuration.
|
||||||
|
///
|
||||||
|
/// The config file will be named `$OUT_DIR/<triple>/pyo3-build-config.txt`.
|
||||||
|
///
|
||||||
|
/// Must be called from a build script, returns `None` if not.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[cfg(feature = "resolve-config")]
|
||||||
|
fn resolve_cross_compile_config_path() -> Option<PathBuf> {
|
||||||
|
env::var_os("TARGET").map(|target| {
|
||||||
|
let mut path = PathBuf::from(env!("OUT_DIR"));
|
||||||
|
path.push(Path::new(&target));
|
||||||
|
path.push("pyo3-build-config.txt");
|
||||||
|
path
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "resolve-config")]
|
#[cfg(feature = "resolve-config")]
|
||||||
fn abi3_config() -> InterpreterConfig {
|
fn abi3_config() -> InterpreterConfig {
|
||||||
let mut interpreter_config = InterpreterConfig::from_reader(Cursor::new(ABI3_CONFIG))
|
let mut interpreter_config = InterpreterConfig::from_reader(Cursor::new(ABI3_CONFIG))
|
||||||
|
@ -158,8 +179,6 @@ pub fn print_feature_cfgs() {
|
||||||
pub mod pyo3_build_script_impl {
|
pub mod pyo3_build_script_impl {
|
||||||
#[cfg(feature = "resolve-config")]
|
#[cfg(feature = "resolve-config")]
|
||||||
use crate::errors::{Context, Result};
|
use crate::errors::{Context, Result};
|
||||||
#[cfg(feature = "resolve-config")]
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
#[cfg(feature = "resolve-config")]
|
#[cfg(feature = "resolve-config")]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -185,7 +204,8 @@ pub mod pyo3_build_script_impl {
|
||||||
Ok(abi3_config())
|
Ok(abi3_config())
|
||||||
} else if let Some(interpreter_config) = make_cross_compile_config()? {
|
} else if let Some(interpreter_config) = make_cross_compile_config()? {
|
||||||
// This is a cross compile and need to write the config file.
|
// This is a cross compile and need to write the config file.
|
||||||
let path = Path::new(DEFAULT_CROSS_COMPILE_CONFIG_PATH);
|
let path = resolve_cross_compile_config_path()
|
||||||
|
.expect("resolve_interpreter_config() must be called from a build script");
|
||||||
let parent_dir = path.parent().ok_or_else(|| {
|
let parent_dir = path.parent().ok_or_else(|| {
|
||||||
format!(
|
format!(
|
||||||
"failed to resolve parent directory of config file {}",
|
"failed to resolve parent directory of config file {}",
|
||||||
|
|
Loading…
Reference in New Issue