是否可以同时使用Java,SWIG和Rust?

kmp*_*kmp 5 java java-native-interface swig rust rust-cargo

我正在尝试从Java调用Rust库,我真的很想使用SWIG从我编写的C头文件生成接口层(我也希望允许常规C客户端调用我的库,因此我认为维护一个接口头很有意义)。

我正在使用MingwRust(GNU ABI)Windows上完成所有这些工作。

我将精确地做我所做的事情以及下面的结果,但是从本质上讲,我最后得到的是UnsatisfiedLinkError。我认为有几件事可能是错误的,但是我不确定,也不确定如何(或是否)可以解决这些问题:

  1. SWIG在函数名称中放置数字(如果编辑testlib_wrap.c在我的示例中生成的文件,则可以看到此代码)。
  2. JNI 文档说我需要-Wl,--add-stdcall-alias在编译时传递参数,但是当我用货物建造时,我不确定该怎么做(如果我直接用rustc建造,可以传递它吗?我在手册页中看不到任何内容)

简而言之,我的问题是:

您如何使用SWIG从Java调用Rust

但是我觉得我正在摸索解决方案的表面,所以答案可能是解决上面的一个或两个问题,所以这就是我目前为止的位置...


我首先使用Cargo创建一个新的Rust库:

cargo new testlib
cd testlib
Run Code Online (Sandbox Code Playgroud)

testlib.h使用内容创建:

void tell_me_the_answer(void);
Run Code Online (Sandbox Code Playgroud)

创建testlib.i具有以下内容的Swig输入文件():

%module testlib
%{
#include "testlib.h"
%}
%include "testlib.h"
Run Code Online (Sandbox Code Playgroud)

运行swig生成一些Java和C:

mkdir testlib
swig -outdir testlib -java -package testlib testlib.i
Run Code Online (Sandbox Code Playgroud)

创建一个Program.java包含以下内容的主Java类():

public final class Program {
    static {
        System.loadLibrary("testlib"); 
    }
    public static void main(final String[] args) {
        testlib.testlib.tell_me_the_answer();
    }
}
Run Code Online (Sandbox Code Playgroud)

编译java:

javac Program.java testlib\testlib.java testlib\testlibJNI.java
Run Code Online (Sandbox Code Playgroud)

编辑src\lib.rs货运实现功能的文件:

#[no_mangle]
pub extern "C" fn tell_me_the_answer() {
    println!("The answer is...APPLES!");
}
Run Code Online (Sandbox Code Playgroud)

创建一个新build.rs文件,以挂接通过gcc-rs库编译swig输出,该库包含:

extern crate gcc;
fn main() {
    gcc::Config::new()
                .file("testlib_wrap.c")
                .include("C:/Program Files/Java/jdk1.8.0_45/include")
                .include("C:/Program Files/Java/jdk1.8.0_45/include/win32")
                .compile("libtestlib.a");
}
Run Code Online (Sandbox Code Playgroud)

编辑Cargo.toml文件,使其包含:

[package]
name = "testlib"
version = "0.1.0"
build = "build.rs"
[lib]
name = "testlib"
crate-type = ["dylib"]
[build-dependencies]
gcc = "0.3"
Run Code Online (Sandbox Code Playgroud)

编译rust项目:

cargo build
Run Code Online (Sandbox Code Playgroud)

运行Java应用程序:

java -Djava.library.path=target\debug Program
Run Code Online (Sandbox Code Playgroud)

得到以下错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: testlib.testlibJNI.tell_me_the_answer()V
    at testlib.testlibJNI.tell_me_the_answer(Native Method)
    at testlib.testlib.tell_me_the_answer(testlib.java:13)
    at Program.main(Program.java:6)
Run Code Online (Sandbox Code Playgroud)

我看了一下货运使我成为依赖依赖行者的DLL,它看起来有点空(就其出口而言),并且至少对我来说,单个函数看起来有点怪异,这是因为名称中的1 s和我认为将删除的@部分--add-stdcall-alias正确吗?

依赖行者输出

我是否关闭了,而依赖项遍历程序中显示的DLL中的名称是我问题的根源?
如果可以,Java_testlib_testlibJNI_tell_me_the_answer那行吗?
如果是这样,我该怎么做(我编辑了_wrap.cSWIG产生的文件以删除1,但不确定如何删除@)?
如果没有,那是什么问题?

kmp*_*kmp 3

我有一个解决方案,但它并不是很漂亮,所以如果有人可以从货物中无缝实现这一点,那将是一个更好的解决方案,但批处理文件暂时对我有用。这就是我所做的......

我放弃了从 Cargo 调用 gcc,从 rust 构建了一个静态库,然后从命令行运行 gcc,将 rust 生成的 staticlib 与 SWIG 生成的代码合并在一起,并创建一个动态库,如下所示...

我改为Cargo.toml

[package]
name = "testlib"
version = "0.1.0"
[lib]
name = "testlib"
crate-type = ["staticlib"]
Run Code Online (Sandbox Code Playgroud)

已删除build.rs

构建静态库:

cargo build
Run Code Online (Sandbox Code Playgroud)

编译 SWIG 输出并将其与刚刚生成的货物链接起来,如下所示:

gcc -shared -o target\debug\testlib.dll "-LC:/Program Files (x86)/Rust stable GNU 1.9/lib/rustlib/i686-pc-windows-gnu/lib" -Ltarget\debug "-IC:/Program Files/Java/jdk1.8.0_45/include" "-IC:/Program Files/Java/jdk1.8.0_45/include/win32" testlib_wrap.c -ltestlib -lws2_32 -luserenv -lgcc_eh -lshell32 -ladvapi32 -Wl,--add-stdcall-alias
Run Code Online (Sandbox Code Playgroud)

现在我有一个testlib.dll在 Dependency Walker 中看起来不错的东西,当我运行它时我看到:

The answer is...APPLES!
Run Code Online (Sandbox Code Playgroud)

这是完全正确的答案。