gpt4 book ai didi

python - 在工作空间中编译时,dylib 无法加载 libstd

转载 作者:行者123 更新时间:2023-11-29 07:51:19 33 4
gpt4 key购买 nike

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

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 是一个也使用 my_lib
  • 的 Python 3 脚本

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

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

如果我执行 cargo buildcargo run -p my_bin,一切正常。问题来自 Python 脚本。

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

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 工作完美)。

使用软件“Dependency Walker”,发现my_lib库找不到Rust的libstd库(前面的报错信息有解释)。

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

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

最佳答案

动态链接有时并不容易。错误消息 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() searches for a compatible Mach-O file in the directories specified by a set of environment variables and the process's current working directory.

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

在您的 shell 中,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 为您注入(inject)这个环境变量。

从哪里可以获得正确的值(value)?运行 rustc --print sysroot 并将 /lib 附加到输出。

如果你想直接运行mybin(没有cargo),你可以这样做:

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 description页。 SIP保护/usr/bin/sbin等文件夹,但不保护/usr/local 例如。

这是什么意思? SIP 做了很多事情,但其中之一是破坏 DYLD_LIBRARY_PATH 值。 Shebang 线像 ...

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

...不会为你工作。您必须使用未安装在系统(和 protected )文件夹中的 Python 解释器。通过 brew 安装一个,安装 Anaconda,...

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

解决此问题的另一种方法是通过 install_name_tool (man install_name_tool )。更多信息在 Why is install_name_tool and otool necessary for Mach-O libraries in Mac Os X? .

例子:

$ 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 未设置,但它有效(Hallo 是通过 hallo 函数来自 libmylib.dylib) 和系统 Python 解释器。

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

如果你不想弄乱它,你可以将mylib crate-type 更改为["rlib", "cdylib"],但这可能不是您想要的。

关于python - 在工作空间中编译时,dylib 无法加载 libstd,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55282165/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com