以前,当代码库为C ++时,我有C ++包装文件,这些文件会链接到代码库,然后运行swig
(C ++ 11支持的第3版)以生成目标语言(Python,JavaScript, C#等)。然后,当然将所有这些文件和库编译成一个共享库,并从所需的语言中调用它。现在,代码库已更改为rust。因此,为了使wig工作,我需要以下内容:
no_mangle
和extern
语法FFI
并编译成staticlib。现在,我swig
在C文件上使用,获取目标语言的接口文件,将所有文件(步骤2和3)和SWIG接口文件组合在一起)成一个共享对象,然后从目标语言进行调用。
所以:
这个方法好吗?
我可以使用免费功能。但是我对如何使成员函数(方法)工作感到困惑。在C ++中,成员函数的第一个参数是隐式this
指针。因此,我可以void*
将类的句柄或结构的C接口返回,将其传递给其他想要存储它的人(例如Firefox的jsctypes),然后再次将reinterpret_cast
其接收为具体/实际类型并调用成员函数在上面。如何使用Rust做到这一点?
例如,对于
pub struct A { id: SomeType, }
impl A {
pub fn some_funct_0(&mut self) {}
pub fn some_funct_1(&self) {}
}
impl SomeTrait for A {
fn some_trait_funct(&mut self) {}
}
那么,如何A
从目标语言(Python,C等)(甚至只是C接口)的对象上访问这些成员函数(应该是非托管的,我猜是在堆上?)?
好的,方法只是常规函数,正如克里斯所说,self
参数与Self
类型具有隐式联系。对于您的示例(稍作修改),使用C代码中的函数应该很简单:
#[repr(C)]
pub struct A { id: u32, }
#[no_mangle]
pub extern fn new_a(id: u32) -> A {
A { id: id }
}
impl A {
#[no_mangle]
pub extern fn some_funct(&self) {
println!("Called some_funct: {}", self.id);
}
}
trait SomeTrait {
extern fn some_trait_funct(&self);
}
impl SomeTrait for A {
#[no_mangle]
extern fn some_trait_funct(&self) {
println!("Called some_trait_funct: {}", self.id);
}
}
请注意,我添加extern
了更改调用约定,并#[no_mangle]
避免#[repr(C)]
在结构上进行名称修饰的操作。如果您的代码创建Box
结构的es并将它们作为原始指针传递给C,则后者是不必要的。但是,我不确定#[no_mangle]
如果有多个特征实现者,如何影响特征方法-如果两者都具有#[no_mangle]
,那么必然会发生某种名称冲突。
现在使用这种类型及其在C中的功能很容易:
#include <stdint.h>
struct A {
uint32_t id;
};
extern struct A new_a(uint32_t id);
extern void some_funct(const struct A *self);
extern void some_trait_funct(const struct A *self);
int main() {
struct A a = new_a(123);
some_funct(&a);
some_trait_funct(&a);
}
该程序可以编译并运行:
% rustc --crate-type=staticlib test.rs
multirust: a new version of 'nightly' is available. run `multirust update nightly` to install it
note: link against the following native artifacts when linking against this static library
note: the order and any duplication can be significant on some platforms, and so may need to be preserved
note: library: System
note: library: pthread
note: library: c
note: library: m
% gcc -o test_use test_use.c libtest.a -lSystem -lpthread -lc -lm
% ./test_use
Called some_funct: 123
Called some_trait_funct: 123
如果接受方法&mut self
:
#[no_mangle]
extern fn some_funct_mut(&mut self) { ... }
您将需要省略const
:
extern void some_funct_mut(struct A *self);
如果接受方法self
:
#[no_mangle]
extern fn some_funct_value(self) { ... }
您将需要按值传递结构:
extern void some_funct_value(struct A self);
尽管如果通过不透明的指针使用该结构,则调用按值将其取值的函数可能很困难,因为C必须知道该结构的确切大小。我相信,不透明指针并不常见。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句