在工作区中编译时,Dylib 无法加载 libstd



>我有一个具有以下结构的项目:

Cargo.toml
my_script.py
my_lib:
- Cargo.toml
- src
my_bin:
- Cargo.toml
- src

哪里:

  • my_lib是一个带有crate-type = ["dylib"]的 Rust 库
  • my_bin是一个使用my_lib的 Rust 二进制应用程序
  • my_script.py是一个 Python 3 脚本,也使用my_lib

Cargo.toml包含一个基本的工作区声明:

[workspace]
members = [
"my_lib",
"my_bin"
]

如果我执行cargo buildcargo run -p my_bin,一切正常.问题出在 Python 脚本上。

在此脚本中,我使用以下代码加载my_liblib 文件:

from ctypes import cdll
from sys import platform
if platform == 'darwin':
prefix = 'lib'
ext = 'dylib'
elif platform == 'win32':
prefix = ''
ext = 'dll'
else:
prefix = 'lib'
ext = 'so'
# Working path:
# lib_path = './my_lib/target/debug/{}my_lib.{}'.format(prefix, ext)
# Buggy "Library not loaded: @rpath/libstd-d00eaa6834e55536.dylib" path:
lib_path = './target/debug/{}my_lib.{}'.format(prefix, ext)
lib = cdll.LoadLibrary(lib_path)
my_func = lib.my_func
my_func()

如果我使用库目录中的库文件(./my_lib/target/...),脚本加载库并执行其功能没有问题。

但是,如果我使用工作区目录(./target/...) 中的库文件,则在尝试加载库时会出现以下错误:

OSError: dlopen(./target/debug/libpeglrs.dylib, 6): Library not loaded: @rpath/libstd-d00eaa6834e55536.dylib

以同样的方式,尝试直接从工作区目标目录执行my_bin会产生相同的错误(即使cargo run -p my_bin完美地工作)。

使用软件"依赖沃克",我发现my_lib库找不到 Rustlibstd库(有前面的错误消息解释)。

手动将包含 Rust 工具链库的路径导出到环境中PATH可以解决此问题。然而,这远非理想且不便携。我也不明白为什么这个问题只在使用工作区目标时发生。

那么,为什么当每个项目目标都可以时,工作区目标找不到 rust 的libstd呢?有没有办法解决这个问题,不需要找到工具链路径和修改环境变量?

动态链接有时并不容易。错误消息Library not loaded: @rpath/libstd-d00eaa6834e55536.dylib非常清楚。您在使用DYLD_LIBRARY_PATH(macOS) 时遇到问题。

TL;博士

您的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 mybintarget/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的帖子:

  • 星期五问答 2009-11-06: 链接和安装名称
  • 星期五问答 2012-11-09: dyld: OS X 上的动态链接

同时运行man dlopen并阅读SEARCHING部分。在这里复制和粘贴它很长,所以,只有第一句话:

dlopen() 在一组环境变量和进程的当前工作目录中搜索兼容的 Mach-O 文件。

您将了解DYLD_LIBRARY_PATH和其他环境变量。

在你的外壳中,echo $DYLD_LIBRARY_PATH命令的输出是什么?我假设它是空的/不包含 Rust 库路径。

将以下行添加到您的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(没有cargo),你可以这样做:

DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH" target/debug/mybin

蟒蛇脚本

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价值。社邦台词像...

  • #!/usr/bin/env python
  • #!/usr/bin/python

。对你不起作用。您必须使用Python解释器,它未安装在系统(和受保护)文件夹中。通过brew安装一个,安装蟒蛇,...

可以禁用 SIP,但不要这样做。

解决此问题的另一种方法是通过install_name_tool(man install_name_toolmylib中的@rpath替换为完整路径。有关详细信息,请参阅为什么 Mac OS X 中的 Mach-O 库需要 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

如您所见,现在没有@rpathDYLD_LIBRARY_PATH没有设置,但它可以使用系统 Python 解释器(Hallo通过libmylib.dylibhallo函数打印

)。请注意一件事 - 例如,与Linux相比,macOS动态库的行为不同。

如果你不想搞砸它,你可以mylibcrate-type更改为["rlib", "cdylib"],但这不是你想要的。

最新更新