I am trying to make Python bindings for a library written in C, using Rust + maturin as glue layer. However, the Python .so
extension does not have my library (let's call it foo
) linked and therefore it fails to load.
My target is MacOS, in case that matters.
I have a Cargo project with the following structure:
src/lib.rs # contains PyO3 bindings for my foo library
build.rs # build script for my wrapper crate
Contents of build.rs
:
use cmake::Config;
const FOO_DIR: &str = "vendor/foo";
fn main() {
let foolib = Config::new(FOO_DIR)
.define("BUILD_SHARED_LIBS", "ON")
.build();
println!("cargo:rustc-link-search=native={}/build", foolib.display());
println!("cargo:rustc-link-lib=dylib=foo");
}
My Cargo.toml
contains nothing special:
[package]
name = "foo_python"
version = "0.1.0"
edition = "2021"
[dependencies]
pyo3 = { version = "0.24.0", features = ["extension-module"] }
[build-dependencies]
cmake = "0.1.54"
cc = "1.2.17"
What I see is that when I run
maturin develop
I get a Python extension package named foo_python
, but it fails to load with the following message:
from foo_python import FooFunction
venv/lib/python3.12/site-packages/foo_python/__init__.py:1: in <module>
from .foo_python import *
E ImportError: dlopen(...venv/lib/python3.12/site-packages/foo_python/foo_python.cpython-312-darwin.so, 0x0002): symbol not found in flat namespace '_foo_SomeFunction'
This _foo_SomeFunction
is defined in libfoo.dylib
that is generated by CMake somewhere at target/debug/build/foo_python-.../out/lib/libfoo.dylib
When I run otool
on this .so
file, I don't see it mentioning my libfoo.dylib
:
otool -L ./venv/lib/python3.12/site-packages/foo_python/foo_python.cpython-312-darwin.so
./venv/lib/python3.12/site-packages/foo_python/foo_python.cpython-312-darwin.so:
@rpath/foo_python.cpython-312-darwin.so (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)
and running nm
on this file shows that the symbol is indeed undefined:
nm ./venv/lib/python3.12/site-packages/foo_python/foo_python.cpython-312-darwin.so | grep SomeFunction
U _foo_SomeFunction
What I observe is that cargo build
or maturin develop
fails if I omit the cargo:rustc-link-*
directives in build.rs
or change the library name, so it does something with these, but it fails to link the foo library into the Python extension.
The same behaviour is seen when I try to link the library statically using
println!("cargo:rustc-link-lib=static=foo");
in my build.rs
.