从Rust中调用C代码

unsafe关键字

0. 新建一个InvokeC的工程

cargo new  InvokeC

1.编辑 src/main.c

extern "C" {
    fn doubler(x: i32) -> i32;
}

fn main() {
    println!("[rust] start");
    unsafe { 
        println!("{}", doubler(6));
    }
}

2. 编辑 src/hello.c

#include stdio.h

int doubler(int x) {
    return x * 2;
}

3.编译C代码

$ cc -c src/hello.c
$ cc -shared hello.o -o libnum.so

4.用rustc 编译代码,并动态链接到 libnum

rustc -l num -L . src/main.rs

5. 运行

LD_LIBRARY_PATH=.  ./main

如果不设置 LD_LIBRARY_PATH 变量, 将会找不到 libnu.so 动态库

6. 也考虑生成静态库

$  ar rcs libnum.a   hello.o

7.链接到静态库

rustc -l static=num -L. src/main.rs  

8.直接运行

./main

9. 如何不用rustc编译, 而是用cargo build或者cargo run
在项目的根目录下,建立一个 build.rs 文件

fn main() {
    println!("cargo:rustc-link-search=.");
    println!("cargo:rustc-link-lib=static=num");
}

就可以了
如果是动态库

    println!("cargo:rustc-link-search=all=src");      //  类似"rustc -L src ..." 
    println!("cargo:rustc-link-lib=dylib=num"); // 类似"rustc -l num"

或者在源代码中 指定链接选项
main.c中

#[link(name = "num", kind = "static")]
extern "C" {
    fn doubler(x: i32) -> i32;
}
...

就可以把 build.rs中

println!("cargo:rustc-link-lib=static=num");

这一行去掉

最后,如果连编译C代码都不想手动去做,可以用一个 cc的库, 在Cargo.toml中添加

[build-dependencies]
cc = "1.0"

注意:是 build-dependencies 而不是 dependencies

然后,将 build.rs改为

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("libnum.a");
}

或者

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("anything");
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注