2016-07-08 2 views
4

Я пытаюсь позвонить в библиотеку Rust от Java, и я действительно хочу использовать SWIG для создания слоя интерфейса из файла заголовка C, который я пишу (я также хочу разрешить постоянным клиентам C вызывать в мою библиотеку, следовательно, я думаю, имеет смысл поддерживать один заголовок интерфейса).Можно ли использовать Java, SWIG и Rust Together?

Я делаю это все на Windows используя Mingw и Rust (GNU ABI).

Я пойду точно, что я сделал, и результат ниже, но по существу я получаю UnsatisfiedLinkError в конце. Есть несколько вещей, которые я думаю, что может быть неправильно, но я не уверен, и я не знаю, как (или если) я могу их исправить:

  1. SWIG ставит номера в имени функции (вы можете увидеть это если вы редактируете файл testlib_wrap.c, который он производит в моем примере).
  2. JNI documentation говорит, что мне нужно передать аргумент -Wl,--add-stdcall-alias при компиляции, но поскольку я строю с грузом, я не уверен, как это сделать (могу ли я передать его, если я буду строить с rustc напрямую, возможно? Я ничего не видел в man page)

Таким образом, в двух словах, мой вопрос:

Как вы звоните в Руст из Java с помощью SWIG?

Но я чувствую, что я царапаю поверхность решения, поэтому ответ может быть решением одной или обеих точек выше, поэтому здесь точно, где я до сих пор ...


Я начинал с создания новой библиотеки ржавчины с помощью Cargo:

cargo new testlib 
cd testlib 

Создать testlib.h с содержимым:

void tell_me_the_answer(void); 

Создать Swig входной файл (testlib.i) со следующим содержимым :

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

Run SWIG, чтобы сгенерировать 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 файл зацепиться при составлении Swig выхода через 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" 

Compile проект ржавчины:

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) 

Я посмотрел на DLL, что груз из меня в dependency walker, и это выглядит вроде пустой (в терминах его экспорт), и единственная функция выглядит немного странно, по крайней мере, для меня, из-за s на имя и @ часть, которую я думаю, что --add-stdcall-alias убрать правильно?

Dependency Walker Output

Am Я закрываю и имя в DLL, как показано в зависимости ходунки корень моей проблемы?
Если бы это было Java_testlib_testlibJNI_tell_me_the_answer, не так ли?
Если да, то как это сделать (я отредактировал файл _wrap.c SWIG, созданный для удаления 1s, но я не уверен, как я избавлюсь от @)?
Если нет, то в чем проблема?

ответ

1

У меня есть решение, но это не очень красиво, поэтому, если кто-то может сделать это без проблем с грузом, это было бы гораздо приятнее, но пакетный файл будет делать для меня пока. Вот что я сделал ...

Я отказался от вызова gcc из груза, создал статический lib из ржавчины, а затем запустил gcc из командной строки, чтобы обработать ржавчину, сгенерированную staticlib, с помощью сгенерированного кода SWIG и создать динамическая библиотека, как так ...

Я изменил Cargo.toml на:

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

удалён build.rs

Встроенный статический Lib:

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! 

Это полностью правильный ответ.

Смежные вопросы