diff --git a/build.rs b/build.rs index 282949cf..7b455aa6 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,7 @@ use std::{env, process::Command}; use pyo3_build_config::{ - bail, ensure, + bail, cargo_env_var, ensure, env_var, errors::{Context, Result}, InterpreterConfig, PythonImplementation, PythonVersion, }; @@ -22,7 +22,10 @@ fn ensure_python_version(interpreter_config: &InterpreterConfig) -> Result<()> { fn ensure_target_architecture(interpreter_config: &InterpreterConfig) -> Result<()> { // Try to check whether the target architecture matches the python library - let rust_target = match env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap().as_str() { + let rust_target = match cargo_env_var("CARGO_CFG_TARGET_POINTER_WIDTH") + .unwrap() + .as_str() + { "64" => "64-bit", "32" => "32-bit", x => bail!("unexpected Rust target pointer width: {}", x), @@ -55,14 +58,14 @@ fn ensure_target_architecture(interpreter_config: &InterpreterConfig) -> Result< } fn get_rustc_link_lib(config: &InterpreterConfig) -> Result { - let link_name = if env::var_os("CARGO_CFG_TARGET_OS").unwrap() == "windows" { + let link_name = if cargo_env_var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { if config.abi3 { // Link against python3.lib for the stable ABI on Windows. // See https://www.python.org/dev/peps/pep-0384/#linkage // // This contains only the limited ABI symbols. "pythonXY:python3".to_owned() - } else if env::var_os("CARGO_CFG_TARGET_ENV").unwrap() == "gnu" { + } else if cargo_env_var("CARGO_CFG_TARGET_ENV").unwrap() == "gnu" { // https://packages.msys2.org/base/mingw-w64-python format!( "pythonXY:python{}.{}", @@ -103,8 +106,8 @@ fn rustc_minor_version() -> Option { } fn emit_cargo_configuration(interpreter_config: &InterpreterConfig) -> Result<()> { - let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); - let is_extension_module = env::var_os("CARGO_FEATURE_EXTENSION_MODULE").is_some(); + let target_os = cargo_env_var("CARGO_CFG_TARGET_OS").unwrap(); + let is_extension_module = cargo_env_var("CARGO_FEATURE_EXTENSION_MODULE").is_some(); match (is_extension_module, target_os.as_str()) { (_, "windows") => { // always link on windows, even with extension module @@ -144,7 +147,7 @@ fn emit_cargo_configuration(interpreter_config: &InterpreterConfig) -> Result<() _ => {} } - if env::var_os("CARGO_FEATURE_AUTO_INITIALIZE").is_some() { + if cargo_env_var("CARGO_FEATURE_AUTO_INITIALIZE").is_some() { if !interpreter_config.shared { bail!( "The `auto-initialize` feature is enabled, but your python installation only supports \ @@ -179,6 +182,9 @@ fn emit_cargo_configuration(interpreter_config: &InterpreterConfig) -> Result<() /// (including `pyo3-macros-backend` during macro expansion). fn configure_pyo3() -> Result<()> { let interpreter_config = pyo3_build_config::make_interpreter_config()?; + if env_var("PYO3_PRINT_CONFIG").map_or(false, |os_str| os_str == "1") { + print_config_and_exit(&interpreter_config); + } ensure_python_version(&interpreter_config)?; ensure_target_architecture(&interpreter_config)?; emit_cargo_configuration(&interpreter_config)?; @@ -207,6 +213,20 @@ fn configure_pyo3() -> Result<()> { Ok(()) } +fn print_config_and_exit(config: &InterpreterConfig) { + println!("\n-- PYO3_PRINT_CONFIG=1 is set, printing configuration and halting compile --"); + println!("implementation: {}", config.implementation); + println!("interpreter version: {}", config.version); + println!("interpreter path: {:?}", config.executable); + println!("libdir: {:?}", config.libdir); + println!("shared: {}", config.shared); + println!("base prefix: {:?}", config.base_prefix); + println!("ld_version: {:?}", config.ld_version); + println!("pointer width: {:?}", config.calcsize_pointer); + + std::process::exit(101); +} + fn main() { // Print out error messages using display, to get nicer formatting. if let Err(e) = configure_pyo3() { diff --git a/guide/src/building_and_distribution.md b/guide/src/building_and_distribution.md index 4b5b869b..54a81f30 100644 --- a/guide/src/building_and_distribution.md +++ b/guide/src/building_and_distribution.md @@ -17,25 +17,34 @@ You can override the Python interpreter by setting the `PYO3_PYTHON` environment Once the Python interpreter is located, `pyo3-build-config` executes it to query the information in the `sysconfig` module which is needed to configure the rest of the compilation. -To validate the configuration which PyO3 will use, you can run the `print-config` binary from the `pyo3-build-config` crate. An example usage of this binary is shown below: +To validate the configuration which PyO3 will use, you can run a compilation with the environment variable `PYO3_PRINT_CONFIG=1` set. An example output of doing this is shown below: -```bash -# (First, clone the PyO3 git repository) -$ cd path/to/pyo3/repository -$ cd pyo3-build-config -$ cargo run --bin print-config -cargo:rerun-if-env-changed=PYO3_PYTHON -cargo:rerun-if-env-changed=VIRTUAL_ENV -cargo:rerun-if-env-changed=CONDA_PREFIX -cargo:rerun-if-env-changed=PATH -implementation: CPython -interpreter version: 3.8 -interpreter path: Some("/usr/bin/python") -libdir: Some("/usr/lib") -shared: true -base prefix: Some("/usr") -ld_version: Some("3.8") -pointer width: Some(8) +```console +$ PYO3_PRINT_CONFIG=1 cargo build + Compiling pyo3 v0.14.1 (/home/david/dev/pyo3) +error: failed to run custom build command for `pyo3 v0.14.1 (/home/david/dev/pyo3)` + +Caused by: + process didn't exit successfully: `/home/david/dev/pyo3/target/debug/build/pyo3-7a8cf4fe22e959b7/build-script-build` (exit status: 101) + --- stdout + cargo:rerun-if-env-changed=PYO3_CROSS + cargo:rerun-if-env-changed=PYO3_CROSS_LIB_DIR + cargo:rerun-if-env-changed=PYO3_CROSS_PYTHON_VERSION + cargo:rerun-if-env-changed=PYO3_PYTHON + cargo:rerun-if-env-changed=VIRTUAL_ENV + cargo:rerun-if-env-changed=CONDA_PREFIX + cargo:rerun-if-env-changed=PATH + cargo:rerun-if-env-changed=PYO3_PRINT_CONFIG + + -- PYO3_PRINT_CONFIG=1 is set, printing configuration and halting compile -- + implementation: CPython + interpreter version: 3.8 + interpreter path: Some("/usr/bin/python") + libdir: Some("/usr/lib") + shared: true + base prefix: Some("/usr") + ld_version: Some("3.8") + pointer width: Some(8) ``` ## Building Python extension modules diff --git a/pyo3-build-config/src/bin/print-config.rs b/pyo3-build-config/src/bin/print-config.rs deleted file mode 100644 index d9da7749..00000000 --- a/pyo3-build-config/src/bin/print-config.rs +++ /dev/null @@ -1,16 +0,0 @@ -use pyo3_build_config::{find_interpreter, get_config_from_interpreter}; - -fn main() -> Result<(), Box> { - let config = get_config_from_interpreter(&find_interpreter()?)?; - - println!("implementation: {}", config.implementation); - println!("interpreter version: {}", config.version); - println!("interpreter path: {:?}", config.executable); - println!("libdir: {:?}", config.libdir); - println!("shared: {}", config.shared); - println!("base prefix: {:?}", config.base_prefix); - println!("ld_version: {:?}", config.ld_version); - println!("pointer width: {:?}", config.calcsize_pointer); - - Ok(()) -} diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index ef0860db..a8ac9972 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -25,13 +25,13 @@ const ABI3_MAX_MINOR: u8 = 9; /// Gets an environment variable owned by cargo. /// /// Environment variables set by cargo are expected to be valid UTF8. -fn cargo_env_var(var: &str) -> Option { +pub fn cargo_env_var(var: &str) -> Option { env::var_os(var).map(|os_string| os_string.to_str().unwrap().into()) } /// Gets an external environment variable, and registers the build script to rerun if /// the variable changes. -fn env_var(var: &str) -> Option { +pub fn env_var(var: &str) -> Option { println!("cargo:rerun-if-env-changed={}", var); env::var_os(var) } diff --git a/pyo3-build-config/src/lib.rs b/pyo3-build-config/src/lib.rs index 38e8a3c2..338e5b42 100644 --- a/pyo3-build-config/src/lib.rs +++ b/pyo3-build-config/src/lib.rs @@ -27,7 +27,7 @@ pub use impl_::{ // Used in PyO3's build.rs #[doc(hidden)] -pub use impl_::make_interpreter_config; +pub use impl_::{cargo_env_var, env_var, make_interpreter_config}; /// Reads the configuration written by PyO3's build.rs ///