From db53229bc7a737d0300ff2c5fbc7ea80040ec263 Mon Sep 17 00:00:00 2001 From: Aviram Hassan Date: Mon, 31 Jan 2022 12:30:30 +0200 Subject: [PATCH] Fix `cargo test` with `extension-module` feature. --- CHANGELOG.md | 1 + guide/src/faq.md | 16 ++++++------- pyo3-build-config/src/lib.rs | 45 +++++++++++++++++++++++++++++------- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfb351f65db..6aedeb90955 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fix `cargo test` with `extension-module` feature. (Requires `cargo +nightly` for now.) #[2135](https://github.com/PyO3/pyo3/pull/2135) - Fix undefined symbol for `PyObject_HasAttr` on PyPy. [#2025](https://github.com/PyO3/pyo3/pull/2025) - Fix memory leak in `PyErr::into_value`. [#2026](https://github.com/PyO3/pyo3/pull/2026) - Fix clippy warning `needless-option-as-deref` in code generated by `#[pyfunction]` and `#[pymethods]`. [#2040](https://github.com/PyO3/pyo3/pull/2040) diff --git a/guide/src/faq.md b/guide/src/faq.md index 42cb5b279c1..3ceaab1c4cb 100644 --- a/guide/src/faq.md +++ b/guide/src/faq.md @@ -15,17 +15,17 @@ PyO3 provides a struct [`GILOnceCell`] which works equivalently to `OnceCell` bu [`GILOnceCell`]: {{#PYO3_DOCS_URL}}/pyo3/once_cell/struct.GILOnceCell.html -## I can't run `cargo test`: I'm having linker issues like "Symbol not found" or "Undefined reference to _PyExc_SystemError"! +## I can't run `cargo test` or `cargo run`: I'm having linker issues like "Symbol not found" or "Undefined reference to _PyExc_SystemError"! -Currently, [#340](https://github.com/PyO3/pyo3/issues/340) causes `cargo test` to fail with linking errors when the `extension-module` feature is activated. For now you can work around this by making the `extension-module` feature optional and running the tests with `cargo test --no-default-features`: +On unix operating systems the `extension-module` feature is required to disable linking against libpython to meet criteria of how Python extension modules should be built. -```toml -[dependencies.pyo3] -{{#PYO3_CRATE_VERSION}} +PyO3 is able to re-enable linking for binaries and tests in the project, but this requires a `cargo` version capable of understanding extra linker arguments. This is only supported on nightly cargoes from February of 2022 or newer. -[features] -extension-module = ["pyo3/extension-module"] -default = ["extension-module"] +```text +# For cargo test +cargo +nightly test +# For cargo run +cargo +nightly run ``` ## I can't run `cargo test`: my crate cannot be found for tests in `tests/` directory! diff --git a/pyo3-build-config/src/lib.rs b/pyo3-build-config/src/lib.rs index 0a4a147c9ba..a7b57c7568b 100644 --- a/pyo3-build-config/src/lib.rs +++ b/pyo3-build-config/src/lib.rs @@ -37,24 +37,36 @@ pub fn use_pyo3_cfgs() { get().emit_pyo3_cfgs(); } -/// Adds linker arguments (for macOS) suitable for PyO3's `extension-module` feature. +/// Adds linker arguments suitable for PyO3's `extension-module` feature. /// /// This should be called from a build script. -/// -/// This is currently a no-op on non-macOS platforms, however may emit additional linker arguments -/// in future if deemed necessarys. +#[cfg(feature = "resolve-config")] pub fn add_extension_module_link_args() { + let interpreter_config = get(); + _add_extension_module_link_args( + interpreter_config, &impl_::cargo_env_var("CARGO_CFG_TARGET_OS").unwrap(), std::io::stdout(), ) } -fn _add_extension_module_link_args(target_os: &str, mut writer: impl std::io::Write) { +fn _add_extension_module_link_args( + interpreter_config: &InterpreterConfig, + target_os: &str, + mut writer: impl std::io::Write, +) { if target_os == "macos" { writeln!(writer, "cargo:rustc-cdylib-link-arg=-undefined").unwrap(); writeln!(writer, "cargo:rustc-cdylib-link-arg=dynamic_lookup").unwrap(); } + if target_os != "windows" && target_os != "android" { + let lib_name = interpreter_config.lib_name.as_ref().unwrap(); + writeln!(writer, "cargo:rustc-link-arg-bins=-l{}", lib_name).unwrap(); + writeln!(writer, "cargo:rustc-link-arg-tests=-l{}", lib_name).unwrap(); + writeln!(writer, "cargo:rustc-link-arg-benches=-l{}", lib_name).unwrap(); + writeln!(writer, "cargo:rustc-link-arg-examples=-l{}", lib_name).unwrap(); + } } /// Loads the configuration determined from the build environment. @@ -179,15 +191,32 @@ mod tests { fn extension_module_link_args() { let mut buf = Vec::new(); + let interpreter_cfg = InterpreterConfig { + version: PythonVersion { major: 3, minor: 7 }, + implementation: PythonImplementation::CPython, + shared: true, + abi3: false, + lib_name: Some("test".to_owned()), + lib_dir: None, + executable: None, + pointer_width: None, + build_flags: BuildFlags::default(), + suppress_build_script_link_lines: false, + extra_build_script_lines: vec![], + }; // Does nothing on non-mac - _add_extension_module_link_args("windows", &mut buf); + _add_extension_module_link_args(&interpreter_cfg, "windows", &mut buf); assert_eq!(buf, Vec::new()); - _add_extension_module_link_args("macos", &mut buf); + _add_extension_module_link_args(&interpreter_cfg, "macos", &mut buf); assert_eq!( std::str::from_utf8(&buf).unwrap(), "cargo:rustc-cdylib-link-arg=-undefined\n\ - cargo:rustc-cdylib-link-arg=dynamic_lookup\n" + cargo:rustc-cdylib-link-arg=dynamic_lookup\n\ + cargo:rustc-link-arg-bins=-ltest\n\ + cargo:rustc-link-arg-tests=-ltest\n\ + cargo:rustc-link-arg-benches=-ltest\n\ + cargo:rustc-link-arg-examples=-ltest\n" ); } }