maturin
maturin copied to clipboard
Link errors on macOS when a dependency which also uses pyo3 has a cdylib target
Bug Description
I have two crates, cell and mitochondria, where cell depends on mitochondria. Each has pyo3 bindings on its own. If mitochondria has cdylib as crate-type, trying to maturin build on mac os will fail with pyo3 linker errors, with only the default crate-type rlib or on ubuntu and windows it works. I've made a minimal example with github actions at https://github.com/konstin/maturin-mac-os-dep-repro.
The error looks like it's missing the link-arg=-undefined/link-arg=dynamic_lookup, even though they are present and work for the top level crate.
[package]
name = "mitochondria"
version = "0.1.0"
edition = "2021"
[lib]
# REMOVE cdyblib FROM THE LINE BELOW TO MAKE THIS PASS
crate-type = ["cdylib", "rlib"]
[dependencies]
pyo3 = { version = "0.17.1", features = ["extension-module"] }
[package]
name = "cell"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
pyo3 = { version = "0.17.1", features = ["extension-module"] }
mitochondria = { path = "mitochondria" }
Your Python version (python -V)
3.8
Your pip version (pip -V)
22.2.2
What bindings you're using
pyo3
Does cargo build work?
n/a, this is a linker error
If on windows, have you checked that you aren't accidentally using unix path (those with the forward slash /)?
- [x] Yes
Steps to Reproduce
See minimal example at https://github.com/konstin/maturin-mac-os-dep-repro
Ubuntu, passing: https://github.com/konstin/maturin-mac-os-dep-repro/runs/8144523404?check_suite_focus=true Mac os, failing: https://github.com/konstin/maturin-mac-os-dep-repro/runs/8144523536?check_suite_focus=true
The error looks like it's missing the link-arg=-undefined/link-arg=dynamic_lookup, even though they are present and work for the top level crate.
I think it's because we are using cargo rustc which only applies these flags to top level crate.
See also https://github.com/PyO3/setuptools-rust/issues/235
Any workarounds for this?
@mlucool If you mean https://github.com/deshaw/nbstripout-fast/pull/3 you can feature-gate the extension-module feature of pyo3.
[dependencies]
pyo3 = "0.17.3"
[features]
default = ["extension-module"]
extension-module = ["pyo3/extension-module"]
Then you can build bin bindings with maturin build --no-default-features to disable extension-module feature. When using cibuildwheel you can pass --no-default-features option via MATURIN_PEP517_ARGS="--no-default-features" env var.
@messense I tried feature-gating the python bindings as you said by setting
# Cargo.toml
[features]
default = ["extension-module"]
extension-module = ["pyo3/extension-module"]
and
# pyproject.toml
[tool.maturin]
bindings = "bin"
to match what you suggested above.
When I tried to build the project using maturin build --no-default-features, I got a binary - which is what I want - but when I just did maturin build, I got a binary also. Interestingly, the only thing that allowed me to build python bindings was removing tool.maturin.bindings = "bin" from pyproject.toml - but when I did that, I could no longer build the python bindings. Here's a table of the resulting build artifact that I get when I change settings with the different build commands:
maturin build |
maturin build --no-default-features |
|
|---|---|---|
tool.maturin.bindings = "bin" |
bin | bin |
No tool.maturin settings |
python bindings | python bindings |
In summary, I wasn't able to get --no-default-features to act as a feature gate to allow me to switch from building bin to building the python bindings. What did I miss here? :thinking:
@peytondmurray Have you tried override bindings type in cli? maturin build -b pyo3.
@messense Thanks for the help - overriding the bindings type in CLI does work, but I'm still getting macOS build issues using cibuildwheel even after feature-gating the extension-module as you suggested above. From the log I've confirmed that the build command used on the runner is correct:
Running `maturin pep517 build-wheel -i /private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/cibw-run-klnop_4a/cp39-macosx_arm64/build/venv/bin/python --compatibility off --no-default-features`
but the build still fails at the linking stage for binary output :thinking:. I can keep poking around with this, maybe there's something else I'm doing wrong here.
I'm also not sure if this helps, but cibuildwheel recently added the option to pass CLI args to the build backend with the CIBW_BUILD_SETTINGS variable: https://github.com/pypa/cibuildwheel/pull/1244 which could be useful here too.
Not sure why, but with some debugging it show that even when extension-module feature disabled CARGO_FEATURE_EXTENSION_MODULE env var still presents:
https://github.com/PyO3/pyo3/blob/a71905052e9320767a1275a85b07e2dc895a17e0/pyo3-build-config/src/impl_.rs#L710
which in turn causes pyo3 to not emit libpython link args.
cc @davidhewitt
Reproduce steps:
git clone https://github.com/peytondmurray/nbstripout-fast.git
cd nbstripout-fast
git checkout add-bin
maturin build --no-default-features
PYO3_PRINT_CONFIG looks fine to me
$ PYO3_PRINT_CONFIG=1 maturin build --no-default-features
📦 Including license file "/Users/messense/Projects/nbstripout-fast/LICENSE.txt"
🐍 Found CPython 3.11 at /Users/messense/.pyenv/versions/3.11.0/bin/python3
📡 Using build options bindings from pyproject.toml
Compiling pyo3-ffi v0.16.6
error: failed to run custom build command for `pyo3-ffi v0.16.6`
Caused by:
process didn't exit successfully: `/Users/messense/Projects/nbstripout-fast/target/debug/build/pyo3-ffi-2eeeb1eb9310c032/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_CROSS_PYTHON_IMPLEMENTATION
cargo:rerun-if-env-changed=PYO3_PRINT_CONFIG
-- PYO3_PRINT_CONFIG=1 is set, printing configuration and halting compile --
implementation=CPython
version=3.11
shared=true
abi3=false
lib_name=python3.11
lib_dir=/Users/messense/.pyenv/versions/3.11.0/lib
executable=/Users/messense/.pyenv/versions/3.11.0/bin/python3
pointer_width=64
build_flags=
suppress_build_script_link_lines=false
note: unset the PYO3_PRINT_CONFIG environment variable and retry to compile with the above config
💥 maturin failed
Caused by: Failed to build a native library through cargo
Caused by: Cargo build finished with "exit status: 101": `"cargo" "rustc" "--no-default-features" "--manifest-path" "/Users/messense/Projects/nbstripout-fast/Cargo.toml" "--message-format" "json" "--bin" "nbstripout-fast"`
xref https://github.com/rust-lang/cargo/issues/9235
there is an implicit dependency from a binary to the library
For future reference, i've confirmed that changing
- name: Build wheels - x86_64
uses: PyO3/maturin-action@v1
with:
target: x86_64
to
- name: Build wheels - x86_64
uses: PyO3/maturin-action@v1
with:
target: x86_64
env:
RUSTFLAGS: "-C link-arg=-undefined -C link-arg=dynamic_lookup"
is a workaround
I'm not sure where to document that properly, it's definitely a rare problem.