首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从其他语言访问锈蚀

如何从其他语言访问锈蚀
EN

Stack Overflow用户
提问于 2015-05-07 06:46:27
回答 2查看 2.3K关注 0票数 9

以前,当代码库在C++中时,我有C++包装文件,它将链接到代码库,我将运行swig (用于C++11支持的版本3)来为目标语言(Python、JavaScript、C#等)生成接口文件。然后,当然,将所有这些文件和库编译成一个共享对象,并让它从所需的语言中调用。现在,代码库正被更改为生锈。因此,要想工作,我有以下几点:

  1. 主要生锈代码文件编译成一个rlib。
  2. 这个文件调用主代码库,但使用no_mangleextern语法作为FFI,并编译成一个静态库。
  3. 调用锈蚀包装器的C文件,是它的副本。

现在我对C文件使用swig,获取目标语言的接口文件,将所有文件(步骤2和步骤3)和SWIG接口文件组合成一个共享对象并从目标语言调用。

所以:

  1. 这个方法好吗?
  2. 我可以得到免费的功能去工作。但是,我对如何使成员函数(方法)工作感到困惑。在C++中,成员函数的第一个参数是隐式this指针。因此,我可以将一个void*句柄返回给类或结构到C接口,它会将它传递给想要存储它的其他人(例如,jsctypes ),然后在再次接收到reinterpret_cast到具体/实际类型,并调用它上的成员函数。我该怎么用铁锈做这件事?

例如,

代码语言:javascript
复制
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接口?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-07 08:25:24

嗯,方法只是正则函数,正如Chris所说,self参数与Self类型有隐式联系。对于您的示例(稍微修改一下),使用C代码中的函数应该是简单明了的:

代码语言:javascript
复制
#[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)]。如果您的代码创建了结构的Boxes并将它们作为原始指针传递给C,则没有必要使用后者。但是,我不确定如果有多个特性实现者,#[no_mangle]会如何影响特性方法--如果两者都有#[no_mangle],必然会出现某种名称冲突。

现在,使用这种类型及其C中的函数很容易:

代码语言:javascript
复制
#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);
}

该程序编译并工作:

代码语言:javascript
复制
% 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

If方法接受&mut self

代码语言:javascript
复制
#[no_mangle]
extern fn some_funct_mut(&mut self) { ... }

您需要省略const

代码语言:javascript
复制
extern void some_funct_mut(struct A *self);

If方法接受self

代码语言:javascript
复制
#[no_mangle]
extern fn some_funct_value(self) { ... }

您需要按值传递结构:

代码语言:javascript
复制
extern void some_funct_value(struct A self);

虽然如果通过不透明指针使用结构,但调用按值取其值的函数可能很困难,因为C必须知道结构的确切大小。我认为,这并不是不透明指针的普遍现象。

票数 6
EN

Stack Overflow用户

发布于 2015-05-11 10:01:23

好的,当我在公认的答案中评论说我不能使用这种方法时,我最后做了这样的事情,让其他人来评论:

编译为rlib的后端锈蚀代码

代码语言:javascript
复制
pub trait TestTrait {
    fn trait_func(&mut self) -> i32;
}

pub struct TestStruct {
    value: i32,
}

impl TestStruct {
    pub fn new(value: i32) -> TestStruct {
        TestStruct {
            value: value,
        }
    }

    pub fn decrement(&mut self, delta: i32) {
        self.value -= delta;
    }
}

impl TestTrait for TestStruct {
    fn trait_func(&mut self) -> i32 {
        self.value += 3;
        self.value
    }
}

链接到上面的rlib并编译成staticlib (即,Linux中的.a等)的铁锈包装器:

代码语言:javascript
复制
#[no_mangle]
pub extern fn free_function_wrapper(value: i32) -> i32 {
    rustlib::free_function(value)
}

#[no_mangle]
pub extern fn new_test_struct_wrapper(value: i32) -> *mut libc::c_void {
    let obj = rustlib::TestStruct::new(value);
    unsafe {
        let raw_ptr = libc::malloc(mem::size_of::<rustlib::TestStruct>() as libc::size_t) as *mut rustlib::TestStruct;

        ptr::write(&mut *raw_ptr, obj);
        raw_ptr as *mut libc::c_void
    }
}

#[no_mangle]
pub extern fn test_struct_decrement_wrapper(raw_ptr: *mut libc::c_void, delta: i32) {
    unsafe {
        mem::transmute::<*mut libc::c_void, &mut rustlib::TestStruct>(raw_ptr).decrement(delta);
    }
}

#[no_mangle]
pub extern fn test_struct_trait_function_wrapper(raw_ptr: *mut libc::c_void) -> i32 {
    unsafe {
        mem::transmute::<*mut libc::c_void, &mut rustlib::TestStruct>(raw_ptr).trait_func()
    }
}

C-包装器(api.h & api.c),它链接到上面的staticlib并在需要时编译成共享对象:

代码语言:javascript
复制
extern int32_t free_function_wrapper(int32_t value);

extern void* new_test_struct_wrapper(int32_t value);
extern void test_struct_decrement_wrapper(void* ptr, int32_t delta);
extern int32_t test_struct_trait_function_wrapper(void* ptr);

int32_t free_function(int32_t value) {
  return free_function_wrapper(value);
}

void* new_test_struct(int32_t value) {
  return new_test_struct_wrapper(value);
}

void test_struct_decrement(void* ptr, int32_t value) {
  test_struct_decrement_wrapper(ptr, value);
}

int32_t test_struct_trait_function(void* ptr) {
  return test_struct_trait_function_wrapper(ptr);
}

现在只需在C文件上运行SWIG (我只发布了.c文件--您可以猜到目标语言在哪个.h上运行),由它生成一个interface_wrap.c (默认名称)并编译这些源代码链接,它们针对staticlib获得一个共享对象。

例如,对于python:

代码语言:javascript
复制
swig -python interface.i
gcc -std=c99 -c -fPIC -Wall -Werror -O2 api.c interface_wrap.c -I/usr/include/python2.7
gcc -shared -o _port_sample.so api.o interface_wrap.o -L./ -lrust_wrapper

现在只需调用Python,整个过程就可以了:

代码语言:javascript
复制
$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import port_sample
>>> handle = port_sample.new_test_struct(36)
>>> port_sample.test_struct_decrement(handle, 12)
>>> value = port_sample.test_struct_trait_function(handle)
>>> print value
27
>>> exit()

我希望有人能发现这是有用的和/或可以建议改进等。我也让这个东西工作,并致力于我的github回购:https://github.com/ustulation/rust-ffi/tree/master/python-swig-rust

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30093769

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档