I am trying to call a function from a local vendor shared object.
I created an example to explain it.
So in main.rs I am trying to call a function from vendor/libadd.so.
It works when i copy the libadd.so into the ./target/[debug|release]/deps/ folder and run it with cargo. When I execute the binary from command line I get "./target/debug/rust_call_c: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory".
I tried a lot of things like "//println!("cargo:rustc-link-search=dependency=./src/vendor");" in build.rs.
I think it is only a small thing which i miss, but I do not get it.
Hopefully someone can give me a hint how to fix this.
complie to libadd.so with: "gcc -shared -o libadd.so -fPIC add.c"
main.rs
use libc::c_int;
// this extern block links to the libadd library
#[link(name = "add")]
extern "C" {
// this is a foreign function
fn add(a: c_int, b: c_int) -> c_int;
}
fn main() {
let r = unsafe { add(1, 4) };
println!("{}", r);
}
This is about the way a binary that depends on a dynamic library looks for it when run. You can see it with $ ldd ./the-binary.
Now, where does the binary look for the dynamic libraries? You can find all the information in the man page of ld.so.
Long story short, when running_ the binary, the dynamic libraries are searched for in directories:
specified by the -rpath=... flag given, beforehand, to the linker when "compiling",
then in the LD_LIBRARY_PATH environment variable,
then in some places specified by some files in /etc/ld_preload...,
and then in /lib and /usr/lib.
The -L linker parameter is of no use (it's just a sanity check, quite surprising to be honest).
Since you have specified the -C rpath flag to rustc in the Cargo.toml file, I guess it must be the reason it worked in the deps folder. The reason it works with cargo run is that cargo sets the LD_LIBRARY_PATH to include the deps folder.
But more generally, you need to add the -C link-args=-Wl,-rpath=PATH_TO_LIB_HERE to the rust flags, either with the RUSTFLAGS env var, or within the .cargo/config file:
relative to the binary location with the $ORIGIN meta-variable.
RUSTFLAGS='-L src/vendor -C link-args=-Wl,-rpath=$ORIGIN/../../src/vendor' (note the single quotes: $ORIGIN is not an env var but text which needs to be passed verbatim).
So, for instance, you could try to set the rpath to $ORIGIN/ to make it work when the binary and the library are in the same dir.