如何从其他语言访问Rust 以前,当代码库是C++时,我有C++的包装文件,这些文件将链接到代码库,我将运行 SWIG/(C++ 3支持的版本11),生成目标语言的接口文件(Python、JavaScript、C等)。然后,将所有这些文件和库编译成一个共享对象,并从所需的语言调用它。现在,代码库被改为rust。因此,对于swig的工作,我有以下几点: 编译成rlib的主rust代码文件 Rust包装文件,它调用主代码库,但对FFI使用no\u mangle和extern语法,并编译成staticlib 调用锈迹包装器的C文件,它是锈迹包装器的副本

如何从其他语言访问Rust 以前,当代码库是C++时,我有C++的包装文件,这些文件将链接到代码库,我将运行 SWIG/(C++ 3支持的版本11),生成目标语言的接口文件(Python、JavaScript、C等)。然后,将所有这些文件和库编译成一个共享对象,并从所需的语言调用它。现在,代码库被改为rust。因此,对于swig的工作,我有以下几点: 编译成rlib的主rust代码文件 Rust包装文件,它调用主代码库,但对FFI使用no\u mangle和extern语法,并编译成staticlib 调用锈迹包装器的C文件,它是锈迹包装器的副本,rust,swig,Rust,Swig,现在我在C文件上使用swig,获取目标语言的接口文件,将所有文件(步骤2和步骤3)和swig接口文件)合并到一个共享对象中,并从目标语言调用 因此: 这种方法行吗 我可以使用免费函数。然而,我对如何让成员函数(方法)工作感到困惑。在C++中,成员函数的第一个参数是隐式这个< /C>指针。因此,我可以将类或结构的void*句柄返回给C接口,该接口将把它传递给希望存储它的其他人(例如,Firefox的jsctypes),然后在再次接收reinterpret\u cast时将其转换为具体/实际类型并调

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

因此:

  • 这种方法行吗

  • 我可以使用免费函数。然而,我对如何让成员函数(方法)工作感到困惑。在C++中,成员函数的第一个参数是隐式<代码>这个< /C>指针。因此,我可以将类或结构的
    void*
    句柄返回给C接口,该接口将把它传递给希望存储它的其他人(例如,Firefox的jsctypes),然后在再次接收
    reinterpret\u cast
    时将其转换为具体/实际类型并调用其上的成员函数。我如何处理锈迹

  • e、 例如

    pub结构A{id:SomeType,}
    暗示{
    pub fn某些函数0(&mut self){
    pub fn某些函数1(&self){
    }
    将某个特征应用于{
    fn某些特征函数(&mut self){
    }
    

    那么,我如何从目标语言(Python、C等)甚至仅仅是一个C接口访问
    A
    对象(我想应该是非托管的,在堆上?)上的这些成员函数呢?

    好吧,方法只是常规函数,正如Chris所说,
    self
    参数与
    self
    类型有隐式的联系。对于您的示例(稍加修改),使用C代码中的函数应该很简单:

    #[repr(C)]
    发布结构A{id:u32,}
    #[没有损坏]
    酒吧外间新店a(id:u32)->a{
    A{id:id}
    }
    暗示{
    #[没有损坏]
    pub extern fn某些函数(&self){
    println!(“称为某些函数:{},self.id);
    }
    }
    特质{
    外部的某些特征功能(自身);
    }
    将某个特征应用于{
    #[没有损坏]
    外部fn某些特性函数(&self){
    println!(“称为某些特征函数:{},self.id);
    }
    }
    
    请注意,我添加了
    extern
    以更改调用约定,并在结构上添加了
    #[no_mangle]
    以避免名称损坏和
    #[repr(C)]
    。如果代码创建结构的
    Box
    es并将它们作为原始指针传递给C,则不需要后者。但是,我不确定如果有多个trait实现者,
    [no#mangle]
    会如何影响trait方法-如果两个trait实现者都有
    [no#mangle]
    ,那么肯定会有某种名称冲突

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

    #包括
    结构A{
    uint32_t id;
    };
    一个新的外部结构(uint32\t id);
    外部无效某些函数(const struct A*self);
    外部无效某些特征函数(const struct A*self);
    int main(){
    结构A=新的(123);
    一些函数(&a);
    某些特征函数&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

    #[无损坏]
    外部fn某些函数mut(&mut self){…}
    
    您需要省略
    const

    extern void一些函数(结构A*self);
    
    如果接受方法
    self

    #[无损坏]
    某些函数值(自){…}
    
    您需要按值传递结构:

    extern void一些函数值(结构自身);
    

    尽管如果通过不透明指针使用该结构,调用按值获取该结构的函数可能会很困难,因为C必须知道该结构的确切大小。我相信不透明指针并不常见。

    好吧,我在接受的答案中评论说我不能使用这种方法,我最后做了类似的事情,让其他人评论:

    编译到
    rlib
    的后端代码:

    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
    ):

    现在只需在目标语言的C文件上运行
    SWIG
    (我刚刚发布了
    .C
    文件-您可以猜测SWIG将在其上运行的
    .h
    ),获得它生成的
    接口_wrap.C
    ,并编译这些源代码链接,根据
    staticlib
    获取共享对象

    例如,对于python:

    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调用,整个过程就可以正常工作:

    $ 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报告:

    在方法定义中,
    self
    self:self
    的糖分,
    &self
    self:
    &mut-self
    的糖分。当然,
    self
    关键字在Rust中仍然很特别,但是
    A::some_trait_functt
    A::some_functt_0
    仍然是以
    &mut A
    作为第一个参数类型的函数。您可以尝试通过编译器插件创建自己的属性,该插件会自动插入
    no_mangle
    ,为该函数创建一个c头文件并在其上运行swig。注意:当您返回struct by value时,返回值最终为void,实际返回值必须写入函数的第一个参数(addit
    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
    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()