2016-07-08 67 views
4

我想從Java調用Rust庫,我真的想用SWIG從我編寫的C頭文件生成接口層(我也想讓普通的C客戶端調用我的庫,因此我認爲維護一個接口頭是有意義的)。是否可以一起使用Java,SWIG和Rust?

我在Windows上使用MingwRust (GNU ABI)來做這件事。

我會進入到我所做的和下面的結果,但基本上我得到了最後的UnsatisfiedLinkError。有幾件事我認爲可能是錯誤的,但我不確定如何(或如果)我可以修復它們:

  1. SWIG將數字放在函數名稱中(您可以看到這個如果你編輯它在我的例子中產生的testlib_wrap.c文件)。
  2. JNI documentation說我編譯時需要通過參數-Wl,--add-stdcall-alias,但是因爲我正在建造貨物,所以我不知道該怎麼做(如果我直接用rustc構建,我可以通過它嗎?我什麼都看不到在man page

所以,總之,我的問題是:

你如何使用痛飲從Java調用到鏽?

但是我覺得我正在抓一個解決方案的表面,所以答案可能是解決上面的一個或兩個問題,所以這裏就是我到目前爲止......


我開始通過使使用Cargo新鏽庫:

cargo new testlib 
cd testlib 

與內容創建testlib.h

void tell_me_the_answer(void); 

創建了一大口輸入文件(testlib.i)包含以下內容:

%module testlib 
%{ 
#include "testlib.h" 
%} 
%include "testlib.h" 

運行痛飲生成一些Java和C:

mkdir testlib 
swig -outdir testlib -java -package testlib testlib.i 

創建一個主要的Java類(Program.java)與內容:

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

編譯java:

javac Program.java testlib\testlib.java testlib\testlibJNI.java 

編輯貨物製作的src\lib.rs文件實現功能:

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

創建一個新的build.rs文件通過gcc-rs庫,其中包含編譯痛飲輸出掛鉤:

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"); 
} 

編輯Cargo.toml文件,它包含:

[package] 
name = "testlib" 
version = "0.1.0" 
build = "build.rs" 
[lib] 
name = "testlib" 
crate-type = ["dylib"] 
[build-dependencies] 
gcc = "0.3" 

編譯防鏽工程:

cargo build 

運行Java應用程序:

java -Djava.library.path=target\debug Program 

收到以下錯誤:

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) 

我看了一下這貨讓我在dependency walker的DLL,它看起來有點空(在條款的這出口)和單一的功能看起來有點奇怪,至少對我來說,由於名稱@部分,我認爲--add-stdcall-alias將刪除權利?

Dependency Walker Output

上午我關閉,並在DLL的名稱所示的Dependency Walker是我的問題的根源在哪裏?
如果是Java_testlib_testlibJNI_tell_me_the_answer它會起作用嗎?
如果是這樣,我該如何做到這一點(我編輯_wrap.c SWIG產生的文件刪除1,但我不知道我將如何擺脫@)?
如果不是,問題是什麼?

回答

1

我有一個解決方案,但它是不是真的很漂亮,如果任何人可以從貨物這種無縫的,這將是一個好得多的解決方案,但一個批處理文件,我暫時會做。這是我做的...

我放棄了從貨物中調用gcc,從生成一個靜態lib,然後從命令行運行gcc,以使用SWIG生成的代碼生成staticlib,並創建一個像這樣的動態庫...

我改變Cargo.toml到:

[package] 
name = "testlib" 
version = "0.1.0" 
[lib] 
name = "testlib" 
crate-type = ["staticlib"] 

刪除build.rs

內置的靜態庫:

cargo build 

編譯的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 

現在我有一個testlib.dll看起來罰款的Dependency Walker,當我運行它,我看到:

The answer is...APPLES! 

這是完全正確的答案。

相關問題