build: make include dir optional when targeting Windows
This commit is contained in:
parent
cc6fc483a6
commit
a350dd2c20
|
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
### Added
|
### Added
|
||||||
- Add support for `#[pyclass(dict)]` and `#[pyclass(weakref)]` with the `abi3` feature on Python 3.9 and up. [#1342](https://github.com/PyO3/pyo3/pull/1342)
|
- Add support for `#[pyclass(dict)]` and `#[pyclass(weakref)]` with the `abi3` feature on Python 3.9 and up. [#1342](https://github.com/PyO3/pyo3/pull/1342)
|
||||||
- Add FFI definitions `PyOS_BeforeFork`, `PyOS_AfterFork_Parent`, `PyOS_AfterFork_Child` for Python 3.7 and up. [#1348](https://github.com/PyO3/pyo3/pull/1348)
|
- Add FFI definitions `PyOS_BeforeFork`, `PyOS_AfterFork_Parent`, `PyOS_AfterFork_Child` for Python 3.7 and up. [#1348](https://github.com/PyO3/pyo3/pull/1348)
|
||||||
|
- Add support for cross-compiling to Windows without needing `PYO3_CROSS_INCLUDE_DIR`. [#1350](https://github.com/PyO3/pyo3/pull/1350)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338)
|
- Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338)
|
||||||
|
|
90
build.rs
90
build.rs
|
@ -97,9 +97,7 @@ struct CrossCompileConfig {
|
||||||
impl CrossCompileConfig {
|
impl CrossCompileConfig {
|
||||||
fn both() -> Result<Self> {
|
fn both() -> Result<Self> {
|
||||||
Ok(CrossCompileConfig {
|
Ok(CrossCompileConfig {
|
||||||
include_dir: Some(CrossCompileConfig::validate_variable(
|
include_dir: env::var_os("PYO3_CROSS_INCLUDE_DIR").map(Into::into),
|
||||||
"PYO3_CROSS_INCLUDE_DIR",
|
|
||||||
)?),
|
|
||||||
..CrossCompileConfig::lib_only()?
|
..CrossCompileConfig::lib_only()?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -372,9 +370,9 @@ fn build_flags_from_config_map(config_map: &HashMap<String, String>) -> HashSet<
|
||||||
///
|
///
|
||||||
/// [1]: https://github.com/python/cpython/blob/3.8/Lib/sysconfig.py#L348
|
/// [1]: https://github.com/python/cpython/blob/3.8/Lib/sysconfig.py#L348
|
||||||
fn load_cross_compile_from_sysconfigdata(
|
fn load_cross_compile_from_sysconfigdata(
|
||||||
python_paths: CrossCompileConfig,
|
cross_compile_config: CrossCompileConfig,
|
||||||
) -> Result<(InterpreterConfig, HashSet<BuildFlag>)> {
|
) -> Result<(InterpreterConfig, HashSet<BuildFlag>)> {
|
||||||
let sysconfig_path = find_sysconfigdata(&python_paths)?;
|
let sysconfig_path = find_sysconfigdata(&cross_compile_config)?;
|
||||||
let sysconfig_data = parse_sysconfigdata(sysconfig_path)?;
|
let sysconfig_data = parse_sysconfigdata(sysconfig_path)?;
|
||||||
|
|
||||||
let major = sysconfig_data.get_numeric("version_major")?;
|
let major = sysconfig_data.get_numeric("version_major")?;
|
||||||
|
@ -393,7 +391,7 @@ fn load_cross_compile_from_sysconfigdata(
|
||||||
|
|
||||||
let interpreter_config = InterpreterConfig {
|
let interpreter_config = InterpreterConfig {
|
||||||
version: python_version,
|
version: python_version,
|
||||||
libdir: python_paths.lib_dir.to_str().map(String::from),
|
libdir: cross_compile_config.lib_dir.to_str().map(String::from),
|
||||||
shared: sysconfig_data.get_bool("Py_ENABLE_SHARED")?,
|
shared: sysconfig_data.get_bool("Py_ENABLE_SHARED")?,
|
||||||
ld_version,
|
ld_version,
|
||||||
base_prefix: "".to_string(),
|
base_prefix: "".to_string(),
|
||||||
|
@ -407,9 +405,9 @@ fn load_cross_compile_from_sysconfigdata(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_cross_compile_from_headers(
|
fn load_cross_compile_from_headers(
|
||||||
python_paths: CrossCompileConfig,
|
cross_compile_config: CrossCompileConfig,
|
||||||
) -> Result<(InterpreterConfig, HashSet<BuildFlag>)> {
|
) -> Result<(InterpreterConfig, HashSet<BuildFlag>)> {
|
||||||
let python_include_dir = python_paths.include_dir.unwrap();
|
let python_include_dir = cross_compile_config.include_dir.unwrap();
|
||||||
let python_include_dir = Path::new(&python_include_dir);
|
let python_include_dir = Path::new(&python_include_dir);
|
||||||
let patchlevel_defines = parse_header_defines(python_include_dir.join("patchlevel.h"))?;
|
let patchlevel_defines = parse_header_defines(python_include_dir.join("patchlevel.h"))?;
|
||||||
|
|
||||||
|
@ -426,7 +424,7 @@ fn load_cross_compile_from_headers(
|
||||||
|
|
||||||
let interpreter_config = InterpreterConfig {
|
let interpreter_config = InterpreterConfig {
|
||||||
version: python_version,
|
version: python_version,
|
||||||
libdir: python_paths.lib_dir.to_str().map(String::from),
|
libdir: cross_compile_config.lib_dir.to_str().map(String::from),
|
||||||
shared: config_data.get_bool("Py_ENABLE_SHARED")?,
|
shared: config_data.get_bool("Py_ENABLE_SHARED")?,
|
||||||
ld_version: format!("{}.{}", major, minor),
|
ld_version: format!("{}.{}", major, minor),
|
||||||
base_prefix: "".to_string(),
|
base_prefix: "".to_string(),
|
||||||
|
@ -439,17 +437,60 @@ fn load_cross_compile_from_headers(
|
||||||
Ok((interpreter_config, build_flags))
|
Ok((interpreter_config, build_flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn windows_hardcoded_cross_compile(
|
||||||
|
cross_compile_config: CrossCompileConfig,
|
||||||
|
) -> Result<(InterpreterConfig, HashSet<BuildFlag>)> {
|
||||||
|
let (major, minor) = if let Some(version) = cross_compile_config.version {
|
||||||
|
let mut parts = version.split('.');
|
||||||
|
match (
|
||||||
|
parts.next().and_then(|major| major.parse().ok()),
|
||||||
|
parts.next().and_then(|minor| minor.parse().ok()),
|
||||||
|
parts.next(),
|
||||||
|
) {
|
||||||
|
(Some(major), Some(minor), None) => (major, minor),
|
||||||
|
_ => bail!(
|
||||||
|
"Expected major.minor version (e.g. 3.9) for PYO3_CROSS_VERSION, got `{}`",
|
||||||
|
version
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else if let Some(minor_version) = get_abi3_minor_version() {
|
||||||
|
(3, minor_version)
|
||||||
|
} else {
|
||||||
|
bail!("One of PYO3_CROSS_INCLUDE_DIR, PYO3_CROSS_PYTHON_VERSION, or an abi3-py3* feature must be specified when cross-compiling for Windows.")
|
||||||
|
};
|
||||||
|
|
||||||
|
let python_version = PythonVersion {
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
implementation: PythonInterpreterKind::CPython,
|
||||||
|
};
|
||||||
|
|
||||||
|
let interpreter_config = InterpreterConfig {
|
||||||
|
version: python_version,
|
||||||
|
libdir: cross_compile_config.lib_dir.to_str().map(String::from),
|
||||||
|
shared: true,
|
||||||
|
ld_version: format!("{}.{}", major, minor),
|
||||||
|
base_prefix: "".to_string(),
|
||||||
|
executable: PathBuf::new(),
|
||||||
|
calcsize_pointer: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((interpreter_config, get_build_flags_windows()?))
|
||||||
|
}
|
||||||
|
|
||||||
fn load_cross_compile_info(
|
fn load_cross_compile_info(
|
||||||
python_paths: CrossCompileConfig,
|
cross_compile_config: CrossCompileConfig,
|
||||||
) -> Result<(InterpreterConfig, HashSet<BuildFlag>)> {
|
) -> Result<(InterpreterConfig, HashSet<BuildFlag>)> {
|
||||||
let target_family = env::var("CARGO_CFG_TARGET_FAMILY")?;
|
let target_family = env::var("CARGO_CFG_TARGET_FAMILY")?;
|
||||||
// Because compiling for windows on linux still includes the unix target family
|
// Because compiling for windows on linux still includes the unix target family
|
||||||
if target_family == "unix" {
|
if target_family == "unix" {
|
||||||
// Configure for unix platforms using the sysconfigdata file
|
// Configure for unix platforms using the sysconfigdata file
|
||||||
load_cross_compile_from_sysconfigdata(python_paths)
|
load_cross_compile_from_sysconfigdata(cross_compile_config)
|
||||||
} else {
|
} else if cross_compile_config.include_dir.is_some() {
|
||||||
// Must configure by headers on windows platform
|
// Must configure by headers on windows platform
|
||||||
load_cross_compile_from_headers(python_paths)
|
load_cross_compile_from_headers(cross_compile_config)
|
||||||
|
} else {
|
||||||
|
windows_hardcoded_cross_compile(cross_compile_config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,7 +499,7 @@ fn load_cross_compile_info(
|
||||||
/// sysconfig.get_config_vars.
|
/// sysconfig.get_config_vars.
|
||||||
fn get_build_flags(python_path: &Path) -> Result<HashSet<BuildFlag>> {
|
fn get_build_flags(python_path: &Path) -> Result<HashSet<BuildFlag>> {
|
||||||
if env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
|
if env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
|
||||||
return get_build_flags_windows(python_path);
|
return get_build_flags_windows();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut script = "import sysconfig; \
|
let mut script = "import sysconfig; \
|
||||||
|
@ -487,7 +528,7 @@ fn get_build_flags(python_path: &Path) -> Result<HashSet<BuildFlag>> {
|
||||||
Ok(flags)
|
Ok(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_build_flags_windows(_: &Path) -> Result<HashSet<BuildFlag>> {
|
fn get_build_flags_windows() -> Result<HashSet<BuildFlag>> {
|
||||||
// sysconfig is missing all the flags on windows, so we can't actually
|
// sysconfig is missing all the flags on windows, so we can't actually
|
||||||
// query the interpreter directly for its build flags.
|
// query the interpreter directly for its build flags.
|
||||||
//
|
//
|
||||||
|
@ -547,9 +588,12 @@ fn get_rustc_link_lib(config: &InterpreterConfig) -> String {
|
||||||
//
|
//
|
||||||
// This contains only the limited ABI symbols.
|
// This contains only the limited ABI symbols.
|
||||||
if env::var_os("CARGO_FEATURE_ABI3").is_some() {
|
if env::var_os("CARGO_FEATURE_ABI3").is_some() {
|
||||||
format!("python3")
|
"pythonXY:python3".to_owned()
|
||||||
} else {
|
} else {
|
||||||
format!("python{}{}", config.version.major, config.version.minor)
|
format!(
|
||||||
|
"pythonXY:python{}{}",
|
||||||
|
config.version.major, config.version.minor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match config.version.implementation {
|
match config.version.implementation {
|
||||||
|
@ -705,10 +749,8 @@ fn configure(interpreter_config: &InterpreterConfig) -> Result<()> {
|
||||||
let minor = 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");
|
println!("cargo:rustc-cfg=Py_LIMITED_API");
|
||||||
// Check any `abi3-py3*` feature is set. If not, use the interpreter version.
|
// 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 {
|
match get_abi3_minor_version() {
|
||||||
Some(minor) if minor > interpreter_config.version.minor => bail!(
|
Some(minor) if minor > interpreter_config.version.minor => bail!(
|
||||||
"You cannot set a mininimum Python version 3.{} higher than the interpreter version 3.{}",
|
"You cannot set a mininimum Python version 3.{} higher than the interpreter version 3.{}",
|
||||||
minor,
|
minor,
|
||||||
|
@ -763,10 +805,16 @@ fn check_target_architecture(interpreter_config: &InterpreterConfig) -> Result<(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_abi3_minor_version() -> Option<u8> {
|
||||||
|
(PY3_MIN_MINOR..=ABI3_MAX_MINOR)
|
||||||
|
.find(|i| env::var_os(format!("CARGO_FEATURE_ABI3_PY3{}", i)).is_some())
|
||||||
|
}
|
||||||
|
|
||||||
fn abi3_without_interpreter() -> Result<()> {
|
fn abi3_without_interpreter() -> Result<()> {
|
||||||
println!("cargo:rustc-cfg=Py_LIMITED_API");
|
println!("cargo:rustc-cfg=Py_LIMITED_API");
|
||||||
let mut flags = "FLAG_WITH_THREAD=1".to_string();
|
let mut flags = "FLAG_WITH_THREAD=1".to_string();
|
||||||
for minor in PY3_MIN_MINOR..=ABI3_MAX_MINOR {
|
let abi_version = get_abi3_minor_version().unwrap_or(ABI3_MAX_MINOR);
|
||||||
|
for minor in PY3_MIN_MINOR..=abi_version {
|
||||||
println!("cargo:rustc-cfg=Py_3_{}", minor);
|
println!("cargo:rustc-cfg=Py_3_{}", minor);
|
||||||
flags += &format!(",CFG_Py_3_{}", minor);
|
flags += &format!(",CFG_Py_3_{}", minor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,9 +91,11 @@ See https://github.com/japaric/rust-cross for a primer on cross compiling Rust i
|
||||||
|
|
||||||
After you've obtained the above, you can build a cross compiled PyO3 module by setting a few extra environment variables:
|
After you've obtained the above, you can build a cross compiled PyO3 module by setting a few extra environment variables:
|
||||||
|
|
||||||
* `PYO3_CROSS_INCLUDE_DIR`: This variable must be set to the directory containing the headers for the target's Python interpreter. **It is only necessary if targeting Windows platforms**
|
|
||||||
* `PYO3_CROSS_LIB_DIR`: This variable must be set to the directory containing the target's libpython DSO and the associated `_sysconfigdata*.py` file.
|
* `PYO3_CROSS_LIB_DIR`: This variable must be set to the directory containing the target's libpython DSO and the associated `_sysconfigdata*.py` file.
|
||||||
* `PYO3_CROSS_PYTHON_VERSION`: This variable must be set if there are multiple versions of python compiled for a unix machine.
|
* `PYO3_CROSS_PYTHON_VERSION`: Major and minor version (e.g. 3.9) of the target Python installation. This variable is only needed if pyo3 cannot determine the version to target by other means:
|
||||||
|
- From `PYO3_CROSS_INCLUDE_DIR` or abi3-py3* features when targeting Windows, or
|
||||||
|
- if there are multiple versions of python present in `PYO3_CROSS_LIB_DIR` when targeting unix.
|
||||||
|
* `PYO3_CROSS_INCLUDE_DIR`: This variable can optionally be set to the directory containing the headers for the target's Python interpreter when targeting Windows.
|
||||||
|
|
||||||
An example might look like the following (assuming your target's sysroot is at `/home/pyo3/cross/sysroot` and that your target is `armv7`):
|
An example might look like the following (assuming your target's sysroot is at `/home/pyo3/cross/sysroot` and that your target is `armv7`):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue