我想从Rust调用一个C ++动态库(* .so),但是我不想从Rust构建它。像这样
cc::Build::new()
.file("src/foo.cc")
.shared_flag(true)
.compile("libfoo.so");
在某些情况下,我只需要调用几个函数,而不是所有函数。我该怎么用?
答案 0 :(得分:5)
在继续之前,请确保您具有Rust FFI (foreign function interface)的基本概念。
在Rust中,调用C很容易,但是很难调用C ++。
要在Rust中调用C函数,只需用extern
包装它们,进行一些基本的类型转换,有时甚至是unsafe
。
要调用C ++函数,由于Rust没有内置的C ++功能知识,因此您可能需要做很多手动翻译。例如,这是Rust-Qt中文档的一部分:
许多东西直接从C ++转换为Rust:
- 原始类型被映射到Rust的原始类型(例如
bool
)和libc crate提供的类型(例如libc::c_int
)。- 固定大小的数字类型(例如
int8_t
或qint8
)映射到Rust的固定大小类型(例如i8
)。- 指针,引用和值映射到Rust的相应类型。
- C ++名称空间已映射到Rust子模块。
- C ++类和结构映射到Rust结构。这也适用于在 库的API,包括依赖项的模板类。
- 自由功能映射到自由功能。
- 类方法被映射到结构的实现。
- 析构函数映射到
Drop
和CppDeletable
实现。- 函数指针类型映射到Rust的等效表示形式。具有引用或类值的函数指针为 不支持。
static_cast
和dynamic_cast
可通过相应的性状在Rust中使用。Rust标识符的名称根据Rust的命名进行了修改 惯例。
无法直接翻译时:
- C ++库的每个包含文件的内容都放在一个单独的子模块中。
- 方法重载是通过将参数包装在元组中并创建描述每个方法可接受的元组的特征来模拟的。 具有默认参数的方法以相同的方式处理。
- 将单个继承转换为
Deref
和DerefMut
实现,从而允许在派生类上调用基类方法 对象。当deref强制不够时,static_cast
应该是 用于从派生类转换为基类。- 将为每个公共类字段创建etter和setter方法。
尚未实施,但已计划:
- 将C ++
typedef
转换为Rust类型别名。- 为基于C ++运算符方法(issue)的结构实现运算符特征。经营者 当前以带有
op_
前缀的常规函数公开。- 如果在C ++方面存在适用的方法,则对结构实施调试和显示特征。
- 为集合实现迭代器特征。
- 子类化API(issue)。
- 提供对类的公共变量(issue)的访问。
- 提供从枚举到int的转换(在Qt API中使用)。
- 支持嵌套在模板类型中的C ++类型,例如
Class1<T>::Class2
。不打算支持:
- 高级模板用法,例如带有整数模板参数的类型。
- 模板部分专业化。
- 模板方法和函数。
我的建议是将C ++库包装为C库,然后将其称为正式FFI方式,或使用rust-bindgen自动进行包装。
如果您仍然想在Rust中调用C ++,rustcxx似乎是一个方便的工具。
关于库链接,这很简单:
/usr/lib
或/usr/local/lib/
之类的系统库搜索路径中,请确保ldconfig -p
可以找到该库。LD_LIBRARY_PATH
来指定从CLI运行cargo
时库所在的路径。答案 1 :(得分:1)
根据Rust's website,没有官方支持与C ++的链接。相反,您可以尝试使用C库。
他们的users forum中也有关于此问题的主题,用户在此提出了一些旨在解决此问题的第三方项目:
我没有使用它们,所以我不能推荐任何特别的东西或分享我的经验,但是祝你好运:)