【问题标题】:How to use a compiled C .so file in rust如何在 rust 中使用已编译的 C .so 文件
【发布时间】:2020-02-15 07:18:14
【问题描述】:

由于一些建议而更新


系统:macOS 10.14.6

这里想问的问题是如何使用rust调用编译好的.so文件,不好意思,我是这部分的新手。

我有一个非常简单的c文件:

#include "add.h"

int add(int a, int b) {
    return a + b;
}

然后我用gcc-fPIC -shared -o libadd.so add.c编译成.so文件放到lib目录下

然后我在 rust 的 build.rs 文件中写了这个:


use std::env;
use std::path::{Path};

fn main() {
    let pwd_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let path = Path::new(&*pwd_dir).join("lib");
    println!("cargo:rustc-link-search=native={}", path.to_str().unwrap());
    println!("cargo:rustc-link-lib=dylib=add");
    // println!("cargo:rustc-link-lib=static=add");
    // println!("cargo:rerun-if-changed=src/hello.c");
}

我希望我能得到并使用这个函数,main.rs 是:

extern { fn add(a: i32, b: i32) -> i32; }

fn main() {
    let c = unsafe { let d = add(3, 5); d };
    println!("c: {:?}", c);
}

cargo build 可以,但cargo run 出错:

   Compiling hello-from-generated-code-3 v0.1.0 (/Users/niexiaotao/work/rust-server/rust-ffi/hello-from-generated-code-3)
    Finished dev [unoptimized + debuginfo] target(s) in 0.34s
     Running `target/debug/hello-from-generated-code-3`
dyld: Library not loaded: libadd.so
  Referenced from: /Users/niexiaotao/work/rust-server/rust-ffi/hello-from-generated-code-3/target/debug/hello-from-generated-code-3
  Reason: image not found
[1]    81811 abort      cargo run

其他事情:我将 .so 更改为 .a 并且货物运行正常。

示例代码here

感谢您的帮助!

【问题讨论】:

  • 我不知道 rust,但至少你应该使用 c,而不是 c++,因为 (1) 在 c++ 中的符号被破坏,并且 (2) 代码可能需要 c++ 运行时。也就是说,你把它放到文件 *.c 中并使用命令“gcc”而不是“g++”进行编译
  • 谢谢你,我更新了描述
  • Using extern "C" in C++ code 也应该防止名称混淆。在这方面,应该不需要使用 C 编译器而不是 C++。
  • 您的 Cargo.toml 中有 links = "add" 吗?我不确定这是否有必要。编译静态库时适合我。
  • 静态库可以但是bylib(.so)不行,有无link="add"都一样

标签: c rust shared-libraries


【解决方案1】:

我遇到了同样的问题。 Cargo 似乎可以正确构建您的库,因为您明确告诉它在哪里查找文件(使用rustc-link-search)。但是,当你去运行它时,Linux 并不知道它在哪里。

如果您要在编译后的 Rust 二进制文件上运行 ldd,您会得到如下结果:

$ ldd target/debug/hello-from-generated-code-3
        linux-vdso.so.1 (0xabcd)
        libadd.so => not found      <----- ldd can't find your library
        ...

这是因为在 LD_LIBRARY_PATH 中找不到您的 .so 文件。您可以通过将库复制到相关文件夹或仅在运行程序时进行设置来解决此问题。例如,你应该能够说:

LD_LIBRARY_PATH=. cargo run

(或您的 .so 文件所在的任何其他路径 - 不一定是 .

【讨论】:

    【解决方案2】:

    我根本没有使用环境变量。例如,您有 /your-crate/lib/libmystuff.so 共享库。为了链接它,请指定以下内容:

    println!("cargo:rustc-link-search=native=./lib");
    println!("cargo:rustc-link-lib=dylib=mystuff");
    

    注意,没有前缀lib的库,路径是相对的。 以防万一。您还可以使用头文件定义包含文件夹:

    let headers = Path::new("/headers");
    cc::Build::new()
       .file("src/foo.c")
       .include(headers)
       .compile("foo");
    

    在 Linux 上测试。最好的问候。

    【讨论】:

    • @lgor 你好,我在 ubuntu 20.04 也遇到了同样的问题,没看懂你的意思。你能解释一下我应该在哪里写let headers = Path::new("/headers"); cc::Build::new() .file("src/foo.c") .include(headers) .compile("foo");
    • 我有一个.so c++ 库,我想使用它,但 cargo 没有正确构建它
    猜你喜欢
    • 1970-01-01
    • 2016-12-26
    • 2019-01-10
    • 2011-02-21
    • 2021-04-28
    • 2014-01-15
    • 1970-01-01
    • 2013-07-30
    相关资源
    最近更新 更多