动态链接有时并不容易。错误信息Library not loaded: @rpath/libstd-d00eaa6834e55536.dylib
非常清晰。你的问题在于DYLD_LIBRARY_PATH
(macOS)。
简短总结:
你的DYLD_LIBRARY_PATH
中没有包含Rust库路径。请将以下内容添加到~/.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"
解释
我按照你的项目结构进行了操作,唯一不同的是我去掉了_
(例如,my_bin
改为 mybin
,...)。
cargo run --bin mybin
与 target/debug/mybin
的区别
首先,检查一下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)
注意
@rpath
。如果你不知道它是什么,我建议阅读 Mike Ash 的文章:
同时运行
man dlopen
并阅读
SEARCHING
部分。此处太长,无法复制和粘贴,所以只提供第一句话:
dlopen()在由一组环境变量和进程的当前工作目录指定的目录中搜索兼容的Mach-O文件。
你将了解有关
DYLD_LIBRARY_PATH
和其他环境变量的信息。
在你的 shell 中,
echo $DYLD_LIBRARY_PATH
命令的输出是什么?我假设它是空的/不包含Rust库路径。
请将以下行添加到 your
mybin:main.rs
...
println!(
"DYLD_LIBRARY_PATH={}",
std::env::var("DYLD_LIBRARY_PATH").unwrap_or("N/A".to_string())
);
...并运行cargo run --bin mybin
。您应该会看到类似于这样的东西:
DYLD_LIBRARY_PATH=~/.rustup/toolchains/stable-x86_64-apple-darwin/lib
cargo run
会为您注入此环境变量。
您可以从哪里获取正确的值? 运行 rustc --print sysroot
并将结果追加 /lib
。
如果您想直接运行mybin
(而不使用),可以按照以下方式操作:
DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH" target/debug/mybin
Python脚本
将类似的行添加到您的run.py
脚本中:
import os
print('DYLD_LIBRARY_PATH: {}'.format(os.environ.get('DYLD_LIBRARY_PATH', 'N/A')))
如果打印出N/A
,则表示DYLD_LIBRARY_PATH
未设置。您可以采用类似的方式进行修复:
DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH" python run.py
macOS和系统完整性保护
请注意,您无法使用系统Python进行此操作...
$ 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
... 但是你可以使用通过brew
安装的例子...
$ 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:
原因是SIP。SIP在El Capitan中引入,可能会阻碍您。您可能会遇到以下问题:
$ env | grep DYLD
$ echo $DYLD_LIBRARY_PATH
/Users/robertvojta/.rustup/toolchains/stable-x86_64-apple-darwin/lib:
这是SIP描述页面。 SIP 保护像/usr
,/bin
,/sbin
这样的文件夹,但不保护/usr/local
等文件夹。
这意味着什么? SIP会执行许多功能,其中一个功能是删除DYLD_LIBRARY_PATH
值。Shebang行例如...
#!/usr/bin/env python
#!/usr/bin/python
...对你来说将无法工作。您必须使用Python解释器,该解释器未安装在系统(和受保护)文件夹中。通过brew
安装一个解释器,也可以安装Anaconda。
SIP可以被禁用,但不要这样做。
另一种解决方法是通过install_name_tool
(man install_name_tool
)将mylib
中的@rpath
替换为完整路径。更多信息请参见为什么Mach-O库在Mac OS X中需要install_name_tool和otool?。
示例:
$ 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
如您所见,现在没有 @rpath
,也没有设置 DYLD_LIBRARY_PATH
,但使用系统 Python 解释器可以正常工作(hallo
函数从 libmylib.dylib
中打印出 Hallo
)。
请注意一点 - macOS 动态库与 Linux 等其他操作系统的动态库行为不同。
如果您不想处理它,可以将 mylib
的 crate-type
更改为 ["rlib", "cdylib"]
,但这可能不是您想要的。
rustup run beta python3 editor.py
是可以工作的,但仍然无法解释为什么只有工作区存在错误。 - Maelncdylib
构建动态库吗? - E net4