rust - 将 Rust 应用程序与不在运行时链接器搜索路径中的动态库链接

标签 rust dynamic-linking dynamic-library rust-cargo ldd

我有一个共享库,我想动态链接到几个单独的二进制 Cargo 应用程序。我使用 -- -L/path/to/dir 格式将它的位置包含在链接器中,应用程序编译正确,二进制大小显着减少,我预计。但是,当使用 ldd 检查生成的二进制文件时,我收到一条消息说找不到该库:

casey@Gilthar-II:~/bot4/backtester/target/release$ ldd backtester 
    linux-vdso.so.1 =>  (0x00007ffc642f7000)
    libalgobot_util.so => not found

如果我将库添加到 /lib/x86_64-linux-gnu 目录,应用程序可以正常运行。

有没有办法让 Rust 在与二进制文件相同的目录中或二进制文件目录中的 lib 目录中查找 .so 文件以在运行时加载?如果那不可能,有没有办法至少让 Rust 插入它所链接的库的绝对路径?

我试过设置 rpath = true 但没有效果。

最佳答案

这是一个 Minimal, Reproducible Example 表现出与您遇到的相同问题。我创建了一个导出简单加法函数的 C 库。我还创建了一个 Cargo 项目来使用此功能。

dynlink/
├── executable
│   ├── build.rs
│   ├── Cargo.lock
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── library
    ├── awesome_math.c
    └── libawesome_math.so

awesome_math.c

#include <stdint.h>

uint8_t from_the_library(uint8_t a, uint8_t b) {
  return a + b;
}

库被编译为 gcc -g -shared awesome_math.c -o libawesome_math.so

src/main.rs

extern {
    fn from_the_library(a: u8, b: u8) -> u8;
}

fn main() {
    unsafe {
        println!("Adding: {}", from_the_library(1, 2));
    }
}

build.rs

fn main() {
    println!("cargo:rustc-link-lib=dylib=awesome_math");
    println!("cargo:rustc-link-search=native=/home/shep/rust/dynlink/library");
}

Cargo.toml

[package]
name = "executable"
version = "0.1.0"
edition = "2021"

[profile.dev]
rpath = true

进一步调查,我要求 Rust 编译器打印出它要使用的链接器参数:

cargo rustc -- --print link-args

这打印了一堆东西,但重要的一行是:

"-Wl,-rpath,$ORIGIN/../../../../../../.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib"

这是链接器的指令,用于将特定值添加到已完成二进制文件的 rpath。缺少对我们链接到的动态库的任何引用。回想起来,这可能是有道理的,因为编译器如何知道我们要将它包含在 rpath 中?

解决方法是向链接器添加另一个指令。有一些有趣的选项(如 $ORIGIN),但为了简单起见,我们将只使用绝对路径:

cargo rustc -- -C link-args="-Wl,-rpath,/home/shep/rust/dynlink/library/"

生成的二进制文件为 ldd 打印正确的内容,并且在不设置 LD_LIBRARY_PATH 的情况下运行:

$ ldd ./target/debug/executable | grep awesome
    libawesome_math.so => /home/shep/rust/dynlink/library/libawesome_math.so (0x0000ffffb1e56000)
    
$ ./target/debug/executable
Adding: 3

转向使其相对化,我们可以使用 $ORIGIN:

cargo rustc -- -C link-args='-Wl,-rpath,$ORIGIN/../../../library/'

小心为您的 shell 正确转义 $ORIGIN,并记住该路径是相对于可执行文件的,而不是当前工作目录。

另见:

关于rust - 将 Rust 应用程序与不在运行时链接器搜索路径中的动态库链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40602708/

相关文章:

struct - 如何类型转换和继承 Rust 结构?

vector - 增加 Vec<usize> 的最后一个元素

c - 如何不忽略 dyld 的最大版本

iterator - Rust 检查迭代器 : cannot borrow `*` as immutable because it is also borrowed as mutable

rust - 在一个函数调用中无法两次借用自己

rust - 如何在 Rust 中指定链接器路径?

c++ - mysqlclient库联动问题

c++ - 共享库中全局静态变量的析构函数未在 dlclose 上调用

c++ - "C++ dlopen mini HOWTO"是编译动态加载的 C++ 插件库的推荐技术吗?

ada - 厚绑定(bind)动态库: Undefined references