Rust/C++ Dylib Linking issues

Hi there,
Could someone help me with best practices for setting up rust to link to a dylib.

I'm trying to create a mixed Rust/C++ application, and I can't seem to get Rust to link against the dylib generated from my C++ codebase. I'm on a Mac, and using CMake+Clang to build the C++ code out.

I found a related github issue but no resolution: https://github.com/rust-lang/cargo/issues/4421

I get an error:

dyld: Library not loaded: @rpath/libfoo.dylib
  Referenced from: /Users/dhruv/Projects/foo/target/debug/foo
  Reason: image not found

My setup is as follows:

  • Inside my repo, I have a directory called dependencies/libs.
  • I build and install a dylib from my C++ code into this directory
  • I use a build.rs file to tell Cargo what to link against and where to find it
println!("cargo:rustc-link-search={}", lib_dir);
println!("cargo:rustc-link-lib=foo");

So it seems the issue is that while rustc can find it correctly during the build, but it fails to find it when running. I can work around this by copying the dylib next to the exe before running it.

What's the best way to handle this situation?

Thank you in advance. I'll try and make a small sample code base to demonstrate this if my description isn't clear enough.

1 Like

If you link statically, it'll be easier.

For dynamic linking each library contains a path under which it's expected to be, and linking with that library copies the path to the executable. This is not related to the search path.

In your case your dylib says it has to be in the same directory as the executable, so before running the executable you have to copy the dylib there.

You could also change the rpath to an absolute path using otool, and ensure the dylib is there for all users of the executable (i.e. distribute it with an installer).

Use otool -L exefile to find what paths the executable uses.

2 Likes

Thanks. So I followed your advice and have my dylibs in the same directory as the executable and that works.

I'll probably wrap cargo inside my CMake so I can control where they all build to together in a consistent manner.

1 Like

So now the issue is that it runs when I use cargo run, but if I navigate to the target/debug directory and run the exe, it fails to find the dylib again.

./spam
dyld: Library not loaded: @rpath/libfoo.dylib
  Referenced from: /repo/target/debug/./spam
  Reason: image not found
[1]    10710 abort      ./spam

Running ottol -L spam gives me:

otool -L spam
spam:
	@rpath/libfoo.dylib (compatibility version 0.0.0, current version 0.0.0)

How do I execute and bundle this?

You need to copy libfoo to current directory, again.

Usually macOS applications reside in app bundles, and have the rpath set to something like @loader_path/../Frameworks/Foo.framework/Versions/A/Foo

You can use install_name_tool to change this.

Isn't it possible to set some environment variable to force it to load the library from another path? I thought DYLD_LIBRARY_PATH could be the way to do that.