Skip to content

kingrong's blog

尝试rust ffi,rust调用clang

最近试图想用rust做一个小工具,但是rust上目前还没有对应的库,而C语言中有对应的库。想尝试使用这个库,我需要先了解一下rust ffi(Foreign Function Interface)。

要想将rust的ffi应用到一整个库上,首先我们先从一个文件做起。

这篇文章就是对rust ffi 一次小小尝试的记录。

编写一个c,并编译为库

我们在一个新建的rust项目的src目录下,新建一个add.c

//src/add.c
int add(int a, int b) {
    return a+b;
}

在命令行中执行:

clang -c add.c -o libadd.a

将我们新建的c文件编译为一个可以被引入的库文件。现在我们src目录下结构就是这样的:

- src
    - add.c
    - libadd.a
    - main.rs

编写main.rs

我们如果想要在main.rs中调用我们在add.c中定义的add函数,我们需要将它引入,并且在unsafe代码块中使用。

use std::os::raw::c_int;

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

fn main() {
    let result = unsafe { add(1, 2) };
    println!("1 + 2 = {}",result);
}

编译main.rs

也许这个时候,你会试图想要用cargo run来运行你的代码。但是这是行不通的,会报undefined reference错误。因为cargo并不知道我们,我们需要链接的库文件在哪里。

试一试这个:

rustc main.rs -L. -ladd && ./main

你可以看到输出了:

1 + 2 = 3

我们可以使用rustc --help查看-L-l flag分别代表着什么。

  • -L 添加lib搜寻的目录
  • -l 添加lib

使用cargo 编译

想要用cargo编译,需要在项目根目录下新建一个build.rs

cargo 会读取build.rs的输出,来设置我们编译时的配置

在这里我们最小化的一个main.rs就是长这样的

//build.rs
fn main() {
    println!("cargo:rustc-link-search=./src");
    println!("cargo:rustc-link-lib=add");
}

具体更多的可以被cargo识别的配置可以在这里找到:build script

参考


Comments