C中使用Rust代码
在C或C++项目中使用Rust代码主要包括两部分。
- 在Rust中创建C友好的API
- 将Rust项目嵌入到外部构建系统中
除了cargo和meson外,大多数构建系统没有本地Rust支持。因此,最有可能最好是使用cargo来编译crate和所有依赖项。
建立一个项目
照常创建一个新的cargo项目。
通能参数可以告诉cargo生成一个系统库crate,而不是常规的Rust项目。您也可以为库设置不同的输出名称。
[lib]
name = "your_crate"
crate-type = ["cdylib"] # Creates dynamic lib
# crate-type = ["staticlib"] # Creates static lib
构建C API
由于C++没有稳定的ABI,因此我们将C用于不同语言之间的任何互操作。在C和C++代码中使用Rust时也不例外。
# [no_mangle]
Rust编译器处理符号名称的方式与c语言链接器期望的方式不同。因此,需要告知Rust编译器不要对要在Rust之外使用的任何函数进行改动。
extern“ C”
默认情况下,您在Rust中编写的任何函数都将使用Rust ABI(它也是不稳定的)。而当构建FFI API时,我们需要告诉编译器使用系统ABI。
根据您的平台,您可能要特定的ABI版本,这些在此处中进行了说明。
将刚刚的内容总结在一起,您将获得一个大致如下所示的函数。
#[no_mangle]
pub extern "C" fn rust_function() {
}
就像在Rust项目中使用C代码一样,您现在需要将数据转换成其他应用程序可以理解的格式。
链接和更大的项目上下文。
因此,现在只是解决了问题的一半。您现在如何使用它?
这在很大程度上取决于您的项目和/或构建系统
cargo将根据您的平台和设置创建一个my_lib.so/my_lib.dll / my_lib.a 文件。该库可以直接由您的构建系统链接。
但是,从C调用Rust函数需要一个头文件来声明函数签名。
Rust-ffi API中的每个函数都需要具有相应的函数声明。
#[no_mangle]
pub extern "C" fn rust_function() {}
需要这样一个声明:
void rust_function();
有一个工具可以自动执行此过程,称为cbindgen,它可以分析Rust代码,然后从中生成C和C++项目的头文件。
至此,在C语言中调用Rust函数只需添加头文件并调用它们!
#include "my-rust-project.h"
rust_function();