Dynamic linking is not easy sometimes. The error message Library not loaded: @rpath/libstd-d00eaa6834e55536.dylib
is pretty clear. You have a problem with DYLD_LIBRARY_PATH
(macOS).
TL;DR
Your DYLD_LIBRARY_PATH
doesn't contain Rust libraries path. Put following into your ~/.bash_profile
:
source "$HOME/.cargo/env"
export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src"
export DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH"
Explanation
I followed your project structure except one thing - I removed _
(my_bin
-> mybin
, ...).
cargo run --bin mybin
vs target/debug/mybin
As a first thing, check what otool -L target/debug/mybin
says:
target/debug/mybin:
/Users/robertvojta/Work/bar/target/debug/deps/libmylib.dylib (compatibility version 0.0.0, current version 0.0.0)
@rpath/libstd-d4fbe66ddea5f3ce.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
Notice the @rpath
. If you don't know what it is, I'd recommend to read Mike Ash posts:
Also run man dlopen
and read the SEARCHING
section. It's pretty long to copy & paste it here, so, just the first sentence:
dlopen() searches for a compatible Mach-O file in the directories specified by a set of environment variables and the process's current working directory.
You'll learn about DYLD_LIBRARY_PATH
and other environment variables.
In your shell, what's the output of echo $DYLD_LIBRARY_PATH
command? I assume it's empty / does not contain Rust libraries path.
Add following lines to your mybin:main.rs
...
println!(
"DYLD_LIBRARY_PATH={}",
std::env::var("DYLD_LIBRARY_PATH").unwrap_or("N/A".to_string())
);
... and run cargo run --bin mybin
. You should see something like this:
DYLD_LIBRARY_PATH=~/.rustup/toolchains/stable-x86_64-apple-darwin/lib
cargo run
injects this environment variable for you.
From where you can get the right value? Run rustc --print sysroot
and append /lib
to the output.
If you'd like to run mybin
directly (without cargo
), you can do it in this way:
DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH" target/debug/mybin
Python script
Add similar lines to your run.py
script:
import os
print('DYLD_LIBRARY_PATH: {}'.format(os.environ.get('DYLD_LIBRARY_PATH', 'N/A')))
If it prints N/A
, DYLD_LIBRARY_PATH
is not set. You can fix this in a similar way:
DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH" python run.py
macOS & System Integrity Protection
Be aware that you can't use system Python for this ...
$ echo $DYLD_LIBRARY_PATH
~/.rustup/toolchains/stable-x86_64-apple-darwin/lib:
$ /usr/bin/python run.py
DYLD_LIBRARY_PATH: N/A
Traceback (most recent call last):
File "./run.py", line 21, in <module>
lib = cdll.LoadLibrary(lib_path)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ctypes/__init__.py", line 443, in LoadLibrary
return self._dlltype(name)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ctypes/__init__.py", line 365, in __init__
self._handle = _dlopen(self._name, mode)
OSError: dlopen(./target/debug/libmylib.dylib, 6): Library not loaded: @rpath/libstd-d4fbe66ddea5f3ce.dylib
Referenced from: /Users/robertvojta/Work/bar/target/debug/libmylib.dylib
Reason: image not found
... but you can use one installed via brew
for example ...
$ echo $DYLD_LIBRARY_PATH
/Users/robertvojta/.rustup/toolchains/stable-x86_64-apple-darwin/lib:
$ /usr/local/bin/python run.py
DYLD_LIBRARY_PATH: /Users/robertvojta/.rustup/toolchains/stable-x86_64-apple-darwin/lib:
The reason is SIP. SIP was introduced in El Capitan and it can be in your way. You can experience stuff like:
$ env | grep DYLD
$ echo $DYLD_LIBRARY_PATH
/Users/robertvojta/.rustup/toolchains/stable-x86_64-apple-darwin/lib:
Here's the SIP description page. SIP protects folders like /usr
, /bin
, /sbin
, but it doesn't protect /usr/local
for example.
What does it mean? SIP does lot of things, but one of them is trashing DYLD_LIBRARY_PATH
value. Shebang lines like ...
#!/usr/bin/env python
#!/usr/bin/python
... wont work for you. You have to use Python interpreter, which is not installed in system (& protected) folders. Install one via brew
, install Anaconda, ...
SIP can be disabled, but DON'T do this.
Another way how to fix this is to replace @rpath
in your mylib
with a full path via install_name_tool
(man install_name_tool
). More info in Why is install_name_tool and otool necessary for Mach-O libraries in Mac Os X?.
Example:
$ otool -L target/debug/mybin
target/debug/mybin:
/Users/robertvojta/Work/bar/target/debug/deps/libmylib.dylib (compatibility version 0.0.0, current version 0.0.0)
@rpath/libstd-d4fbe66ddea5f3ce.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
$ install_name_tool -change @rpath/libstd-d4fbe66ddea5f3ce.dylib /Users/robertvojta/.rustup/toolchains/stable-x86_64-apple-darwin/lib/libstd-d4fbe66ddea5f3ce.dylib target/debug/libmylib.dylib
$ otool -L target/debug/libmylib.dylib
target/debug/libmylib.dylib:
/Users/robertvojta/Work/bar/target/debug/deps/libmylib.dylib (compatibility version 0.0.0, current version 0.0.0)
/Users/robertvojta/.rustup/toolchains/stable-x86_64-apple-darwin/lib/libstd-d4fbe66ddea5f3ce.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
$ /usr/bin/python run.py
DYLD_LIBRARY_PATH: N/A
Hallo
As you can see, there's no @rpath
now, DYLD_LIBRARY_PATH
is not set, but it works (Hallo
is printed via hallo
function from libmylib.dylib
) with system Python interpreter.
Be aware of one thing - macOS dynamic libraries behave differently when compared to Linux for example.
If you do not want to mess with it, you can change mylib
crate-type
to ["rlib", "cdylib"]
, but that's not what you probably want.