rust-c-call-each-other

Rust调用C语言代码

参考自https://blog.csdn.net/phthon1997/article/details/126469708

创建项目

使用cargo创建新项目

1
cargo new rust_and_c

创建build.rs

1
2
3
4
5
6
7
extern crate cc;

fn main() {
cc::Build::new().file("src/double.c").compile("libdouble.a");
cc::Build::new().file("src/third.c").compile("libthird.a");
}

这里的build.rs:若要创建构建脚本,我们只需在项目的根目录下添加一个 build.rs 文件即可。这样一来, Cargo 就会先编译和执行该构建脚本,然后再去构建整个项目。 导入rust的一个库叫cc,作用肯定就是和c语言调用相关啦,关于具体细节暂时可以不学。 src/double.c和src/third.c都是一会要写的两个c语言文件,指定好他们编译之后的静态库。

编辑Cargo.toml的内容

1
2
3
4
5
6
7
8
9
10
11
[package]
name = "rust_and_c"
version = "0.1.0"
build = "build.rs"

[dependencies]
libc = "0.2"

[build-dependencies]
cc = "1.0"

package这个地方需要添加上整个构建文件build.rs以告知需要提前构建。 build-dependencies就是关于build.rs需要的库。 dependencies是main.rs所需要的库。

创建C语言的文件

src/double.c

1
2
3
4
5
int double_input(int input)
{
return input * 2;
}

third.c

1
2
3
4
5
int third_input(int input)
{
return input * 3;
}

编写rust主函数的内容

main.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extern crate libc;

extern "C" {
fn double_input(input: libc::c_int) -> libc::c_int;
fn third_input(input: libc::c_int) -> libc::c_int;
}

fn main() {
let input = 4;
let output = unsafe { double_input(input) };
let output2: i32 = unsafe { third_input(input) };
println!("{} * 3 = {}", input, output2);
println!("{} * 2 = {}", input, output);
}

为了在rust代码中和c代码一样的类型定义一致,这里使用了为rust准备的libc库,可以放心使用,不用管两者的类型不一致问题。 也要提前使用extern “C”来做一个声明,链接主要就是靠它来做一个类似的接口,extern告知Rust编译器这部分功能由一个外部库提供。 unsafe的作用:rust只能保证自己的代码是安全的,c语言的代码不会给你去做检查,不加unsafe是不行的,涉及到很多底层的操作。

整体代码结构

http://img.singhe.art/20230611185938.png

Rust使用已存在的C语言库

参考https://stackoverflow.com/questions/43826572/where-should-i-place-a-static-library-so-i-can-link-it-with-a-rust-program

编译出静态连接库

假设在目录/home/singheart/Project/cpp_project下有一个square.c的文件,文件内容如下:

1
2
3
int square(int value) {
return value * value;
}

将其编译成libsquare.a放在同一个目录下:

1
2
gcc -c -o square.o square.c
ar -rcs libsquare.a square.o

创建build.rs

1
2
3
fn main() {
println!("cargo:rustc-link-search=/home/singheart/Project/cpp_project");
}

创建main.rs

1
2
3
4
5
6
7
8
9
10
#[link(name = "square")]
extern "C" {
fn square(val: i32) -> i32;
}

fn main() {
let r = unsafe { square(3) };
println!("3 squared is {}", r);
}

编写Cargo.toml

1
2
3
4
5
6
7
8
9
10
11
12
13
[package]
name = "rust-use-c-lib"
version = "0.1.0"
edition = "2021"
build = "build.rs"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
libc = "0.2"

[build-dependencies]
cc = "1.0"