将 Rust 应用程序与不在运行时链接器搜索路径中的动态库链接 [英] Linking Rust application with a dynamic library not in the runtime linker search path

查看:37
本文介绍了将 Rust 应用程序与不在运行时链接器搜索路径中的动态库链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a shared library that I'd like to dynamically link into several separate binary Cargo applications. I include its location in the linker using the -- -L /path/to/dir format and the application compiles correctly with the significant decrease in binary size I expect. However, when checking the generated binary using ldd, I get a message saying that the library couldn't be found:

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

如果我将库添加到 /lib/x86_64-linux-gnu 目录,应用程序运行没有问题.

If I add the library to the /lib/x86_64-linux-gnu directory, the application runs without issue.

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

Is there a way to get Rust to look for .so files in the same directory as the binary or in a directory like lib in the binary's directory to be loaded at runtime? If that's not possible, is there a way to at least get Rust to insert the absolute path of the library it was linked with?

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

I've tried setting rpath = true with no effect.

推荐答案

这里有一个完整的解决方案...

Here's a complete solution...

我创建了一个 C 库,导出一个简单的加法函数.我还创建了一个 Cargo 项目来使用这个功能.

I created a C library exporting a simple addition function. I also created a Cargo project to use this function.

/scratch
├── executable
│   ├── Cargo.lock
│   ├── Cargo.toml
│   ├── build.rs
│   ├── 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.rs

extern crate libc;

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

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=/scratch/library");
}

Cargo.toml

[package]
name = "executable"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
build = "build.rs"

[dependencies]
libc = "*"

[profile.dev]
rpath = true

执行所有这些操作会出现您遇到的相同问题.这称为最小、完整和可验证的示例,您应该在提问时提供一个.如果提供此信息,则此答案可能是在 12 小时前创建的.

Doing all of this exhibits the same problem that you experienced. This is called a Minimal, Complete, and Verifiable Example and you should provide one when asking a question. If this were provided, this answer might have been created 12 hours earlier.

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

Investigating further, I asked the Rust compiler to print out the linker args it was going to use:

cargo rustc -- -Z print-link-args

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

This printed out a bunch of stuff, but the two important lines were

"-Wl,-rpath,$ORIGIN/../../../../root/.multirust/toolchains/stable-2016-11-08-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib"
"-Wl,-rpath,/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib"

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

These are directives to the linker to add specific values to the rpath of the finished binary. Missing is any reference to the dynamic library that we are linking to. In retrospect, this probably makes sense, as how would the compiler know that we want to include it in the rpath?

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

A workaround is to add another directive to the linker. There are interesting options (like $ORIGIN), but for simplicity, we will just use an absolute path:

cargo rustc -- -C link-args="-Wl,-rpath,/scratch/library/"

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

And the resulting binary prints the right thing for ldd and runs without setting LD_LIBRARY_PATH:

$ ldd target/debug/executable | grep awesome
    libawesome_math.so => /scratch/library/libawesome_math.so (0x00007fe859085000)
$ ./target/debug/executable
Adding: 3

<小时>

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

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

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

Be careful to escape $ORIGIN properly for your shell, and remember that the path is relative to the executable, not the current working directory.

这篇关于将 Rust 应用程序与不在运行时链接器搜索路径中的动态库链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆