我有一个共享库,我想动态链接到几个单独的二进制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的目录中的文件?如果这是不可能的,有没有办法至少让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,记住路径是相对于executable的,而不是当前工作目录.

另见:

Rust相关问答推荐

PyReadonlyArray2到Vec T<>

使用模块中的所有模块,但不包括特定模块

Tokio_Postgres行上未显示退回特性的生存期,且生命周期 不够长

如何在递归数据 struct 中移动所有权时变异引用?

`Pin`有没有不涉及不安全代码的目的?

如何在函数中返回自定义字符串引用?

如何在Rust中基于字符串 Select struct ?

Rust移动/复制涉及实际复制时进行检测

使用占位符获取用户输入

Rust与_有何区别?

decltype、dyn、impl traits,重构时如何声明函数的返回类型

在 Bevy 项目中为 TextureAtlas 精灵实施 NearestNeighbor 的正确方法是什么?

如何在 Rust 中将 Vec> 转换为 Vec>?

使用自定义 struct 收集 Vec

为什么 for_each 在释放模式(cargo run -r)下比 for 循环快得多?

为什么允许重新分配 String 而不是 *&String

如何获取包裹在 Arc<> 和 RwLock<> 中的 Rust HashMap<> 的长度?

在 Rust 中为泛型 struct 编写一次特征绑定

如何断言代码不会在测试中编译?

为什么这里需要类型注解?