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

查看:230
本文介绍了将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/'

请小心地为您的外壳正确地转义$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天全站免登陆