diff --git a/Cargo.toml b/Cargo.toml index 915008e4f14..bc113de955f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,7 +98,6 @@ full = [ "indexmap", "eyre", "anyhow", - "pyo3-build-config/export-config" ] [[bench]] diff --git a/guide/src/building_and_distribution.md b/guide/src/building_and_distribution.md index 708436d9cdd..5a3a7ab5944 100644 --- a/guide/src/building_and_distribution.md +++ b/guide/src/building_and_distribution.md @@ -50,8 +50,6 @@ If you save the above output config from `PYO3_PRINT_CONFIG` to a file, it is po If your build environment is unusual enough that PyO3's regular configuration detection doesn't work, using a config file like this will give you the flexibility to make PyO3 work for you. To see the full set of options supported, see the documentation for the [`InterpreterConfig` struct](https://docs.rs/pyo3-build-config/{{#PYO3_DOCS_VERSION}}/pyo3_build_config/struct.InterpreterConfig.html). -The `export-config` feature of the `pyo3-build-config` crate also allows these values to be exported for use in other crates, and `pyo3-build-config` offers a funciton for reading them in and constructing an `InterpreterConfig`. - ## Building Python extension modules Python extension modules need to be compiled differently depending on the OS (and architecture) that they are being compiled for. As well as multiple OSes (and architectures), there are also many different Python versions which are actively supported. Packages uploaded to [PyPI](https://pypi.org/) usually want to upload prebuilt "wheels" covering many OS/arch/version combinations so that users on all these different platforms don't have to compile the package themselves. Package vendors can opt-in to the "abi3" limited Python API which allows their wheels to be used on multiple Python versions, reducing the number of wheels they need to compile, but restricts the functionality they can use. diff --git a/guide/src/features.md b/guide/src/features.md index a4f48083501..92d04815a10 100644 --- a/guide/src/features.md +++ b/guide/src/features.md @@ -81,14 +81,6 @@ The `resolve-config` feature of the `pyo3-build-config` crate controls whether t build script automatically resolves a Python interpreter / build configuration. This feature is primarily useful when building PyO3 itself. By default this feature is not enabled, meaning you can freely use `pyo3-build-config` as a standalone library to read or write PyO3 build configuration files or resolve metadata about a Python interpreter. -### `export-config` - -The `export-config` feature of the `pyo3-build-config` crate controls whether -that crate exports the build configuration for use in other crates. This -feature may be useful if building an additional dependency that requires access -to the Python interpreter used to build PyO3 itself. This feature should be -used with caution as it can impact build portability. - ## Optional Dependencies These features enable conversions between Python types and types from other Rust crates, enabling easy access to the rest of the Rust ecosystem. diff --git a/pyo3-build-config/Cargo.toml b/pyo3-build-config/Cargo.toml index 88c1b1df384..2233dd78a4e 100644 --- a/pyo3-build-config/Cargo.toml +++ b/pyo3-build-config/Cargo.toml @@ -20,9 +20,6 @@ default = [] # script. If this feature isn't enabled, the build script no-ops. resolve-config = [] -# Export the resolved build config into a file for use by e.g. other build scripts. -export-config = ["resolve-config"] - abi3 = [] abi3-py37 = ["abi3-py38"] abi3-py38 = ["abi3-py39"] diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 97f5b4c23eb..1a7e27bd115 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -4,10 +4,11 @@ use std::{ env, ffi::{OsStr, OsString}, fmt::Display, - fs::{self, DirEntry, File}, + fs::{self, DirEntry}, io::{BufRead, BufReader, Read, Write}, path::{Path, PathBuf}, process::{Command, Stdio}, + str, str::FromStr, }; @@ -21,8 +22,6 @@ use crate::{ const MINIMUM_SUPPORTED_VERSION: PythonVersion = PythonVersion { major: 3, minor: 7 }; /// Maximum Python version that can be used as minimum required Python version with abi3. const ABI3_MAX_MINOR: u8 = 9; -/// Name of config file exported by "export-config" feature. -const EXPORT_CONFIG_FILENAME: &str = ".pyo3-export-config"; /// Gets an environment variable owned by cargo. /// @@ -155,25 +154,7 @@ impl InterpreterConfig { } for flag in &self.build_flags.0 { - println!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag) - } - - if cfg!(feature = "export-config") { - let output_path = - Path::new(&cargo_env_var("OUT_DIR").unwrap()).join(EXPORT_CONFIG_FILENAME); - if let Ok(config_file) = File::create(&output_path) { - if self.to_writer(config_file).is_err() { - warn!( - "Failed to export build config - this may be a problem for external crates that \ - depend on the pyo3 config." - ); - } else { - println!( - "cargo:PYO3_EXPORT_CONFIG={}", - output_path.canonicalize().unwrap().to_str().unwrap() - ); - } - } + println!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag); } } @@ -359,13 +340,11 @@ print("mingw", get_platform().startswith("mingw")) InterpreterConfig::from_reader(reader) } - /// Create an InterpreterConfig generated from pyo3-build-config using the "export-config" - /// feature - #[cfg(feature = "export-config")] - pub fn from_pyo3_export_config() -> Result { - InterpreterConfig::from_path(Path::new( - &cargo_env_var("DEP_PYTHON_PYO3_EXPORT_CONFIG").unwrap(), - )) + #[doc(hidden)] + pub fn from_cargo_link_env() -> Result { + // un-escape any newlines in the exported config + let buf = cargo_env_var("DEP_PYTHON_PYO3_CONFIG").unwrap().replace("\\n", "\n"); + InterpreterConfig::from_reader(buf.as_bytes()) } #[doc(hidden)] @@ -448,6 +427,19 @@ print("mingw", get_platform().startswith("mingw")) }) } + #[doc(hidden)] + pub fn to_cargo_link_env(&self) -> Result<()> { + let mut buf = Vec::new(); + self.to_writer(&mut buf)?; + // escape newlines in env var + if let Ok(config) = str::from_utf8(&buf) { + println!("cargo:PYO3_CONFIG={}", config.replace("\n", "\\n")); + } else { + bail!("unable to emit interpreter config to link env for downstream use"); + } + Ok(()) + } + #[doc(hidden)] pub fn to_writer(&self, mut writer: impl Write) -> Result<()> { macro_rules! write_line { @@ -503,7 +495,7 @@ print("mingw", get_platform().startswith("mingw")) Path::new( self.executable .as_ref() - .expect("No interpreter executable!"), + .expect("no interpreter executable"), ), script, envs, @@ -512,13 +504,14 @@ print("mingw", get_platform().startswith("mingw")) /// Run a python script using the executable of this InterpreterConfig. pub fn run_python_script(&self, script: &str) -> Result { - run_python_script( + run_python_script_with_envs( Path::new( self.executable .as_ref() - .expect("No interpreter executable!"), + .expect("no interpreter executable"), ), script, + std::iter::empty::<(&str, &str)>(), ) } } @@ -605,6 +598,11 @@ fn is_abi3() -> bool { cargo_env_var("CARGO_FEATURE_ABI3").is_some() } +#[allow(unused)] +pub fn link_env_var_set() -> bool { + cargo_env_var("DEP_PYTHON_PYO3_CONFIG").is_some() +} + #[derive(Debug, PartialEq)] struct TargetInfo { /// The `arch` component of the compilation target triple. @@ -1945,19 +1943,4 @@ mod tests { .expect("failed to run Python script"); assert_eq!(out.trim_end(), "42"); } - - #[test] - #[cfg(feature = "export-config")] - fn test_emit_pyo3_configs_roundtrip() { - let interpreter = make_interpreter_config() - .expect("could not get InterpreterConfig from installed interpreter"); - interpreter.emit_pyo3_cfgs(); - // config path env var is not set during testing of this crate alone, as it relies on the - // pyo3 python links manifest key, so we have to hard-code the same path - let output_path = - Path::new(&cargo_env_var("OUT_DIR").unwrap()).join(EXPORT_CONFIG_FILENAME); - let reimported_interpreter = InterpreterConfig::from_path(output_path) - .expect("could not generated InterpreterConfig from exported config"); - assert_eq!(interpreter, reimported_interpreter); - } } diff --git a/pyo3-build-config/src/lib.rs b/pyo3-build-config/src/lib.rs index 8a52fe0dfa5..be1165c9db2 100644 --- a/pyo3-build-config/src/lib.rs +++ b/pyo3-build-config/src/lib.rs @@ -61,7 +61,6 @@ fn _add_extension_module_link_args(target_os: &str, mut writer: impl std::io::Wr /// Loads the configuration determined from the build environment. /// /// Because this will never change in a given compilation run, this is cached in a `once_cell`. -#[doc(hidden)] #[cfg(feature = "resolve-config")] pub fn get() -> &'static InterpreterConfig { static CONFIG: OnceCell = OnceCell::new(); @@ -72,6 +71,8 @@ pub fn get() -> &'static InterpreterConfig { Ok(abi3_config()) } else if impl_::cross_compile_env_vars().any() { InterpreterConfig::from_path(DEFAULT_CROSS_COMPILE_CONFIG_PATH) + } else if impl_::link_env_var_set() { + InterpreterConfig::from_cargo_link_env() } else { InterpreterConfig::from_reader(Cursor::new(HOST_CONFIG)) } diff --git a/pyo3-ffi/build.rs b/pyo3-ffi/build.rs index c8d65d5d1c2..98e78c9c4b9 100644 --- a/pyo3-ffi/build.rs +++ b/pyo3-ffi/build.rs @@ -69,6 +69,9 @@ fn emit_link_config(interpreter_config: &InterpreterConfig) -> Result<()> { } } + // serialize the whole interpreter config in DEP_PYTHON_PYO3_CONFIG + interpreter_config.to_cargo_link_env()?; + Ok(()) }