kmp kmp - 1 year ago 137
Java Question

Is it Possible to use Java, SWIG and Rust Together?

I am trying to call into a Rust library from Java and I really want to use SWIG to generate the interface layer from a C header file that I write (I also want to allow regular C clients to call into my library, hence I think it makes sense to maintain one interface header).

I am doing this all on Windows using Mingw and Rust (GNU ABI).

I will go into exactly what I did and the result below but essentially I am getting an UnsatisfiedLinkError at the end. There are a couple of things that I think may be wrong but I am not sure and I am not sure how (or if) I can fix them:

  1. SWIG puts numbers in the function name (you can see this if you edit the
    file it produces in my example).

  2. The JNI documentation says I need to pass the argument
    when compiling but as I am building with cargo I am not sure how to do that (can I pass it if I build with rustc directly perhaps? I could not see anything in the man page)

So in a nutshell, my question is:

How do you call into Rust from Java using SWIG?

But I feel like I am scratching the surface of a solution so the answer may be resolving one or both of the points above so here is exactly where I am so far...

I start by making a new Rust library using Cargo:

cargo new testlib
cd testlib

with the contents:

void tell_me_the_answer(void);

Create a swig input file (
) with the following contents:

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

Run swig to generate some Java and C:

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

Create a main java class (
) with the contents:

public final class Program {
static {
public static void main(final String[] args) {

Compile the java:

javac testlib\ testlib\

Edit the
file that cargo made to implement the function:

pub extern "C" fn tell_me_the_answer() {
println!("The answer is...APPLES!");

Create a new
file to hook in compiling the swig output via the gcc-rs library, which contains:

extern crate gcc;
fn main() {
.include("C:/Program Files/Java/jdk1.8.0_45/include")
.include("C:/Program Files/Java/jdk1.8.0_45/include/win32")

Edit the
file so that it contains:

name = "testlib"
version = "0.1.0"
build = ""
name = "testlib"
crate-type = ["dylib"]
gcc = "0.3"

Compile the rust project:

cargo build

Run the java application:

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

Get the following error:

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(
at Program.main(

I had a look at the DLL that cargo made me in dependency walker and it looks kind of empty (in terms of it's exports) and the single function looks a bit weird, to me at least, due to the 1s in the name and the @ part which I think the
would remove right?

Dependency Walker Output

Am I close and the name in the DLL as shown in dependency walker is the root of my problem?

If it were
would it work?

If so, how do I make it so (I edited the
file SWIG produced to remove the 1s but I am not sure how I will get rid of the @)?

If not, what's the problem?

kmp kmp
Answer Source

I have a solution, but it is not really beautiful so if anyone can make this seamless from cargo that would be a much nicer solution but a batch file will do for me for the time being. Here is what I did...

I gave up on calling gcc from cargo, built a static lib from rust and then ran gcc from the command line to munge the rust generated staticlib in with the SWIG generated code and create a dynamic library like so...

I changed Cargo.toml to:

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


Built the static lib:

cargo build

Compiled the SWIG output and linked it with what cargo just produced like this:

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

Now I have a testlib.dll that looks fine in Dependency Walker and when I run it I see:

The answer is...APPLES!

Which is totally the right answer.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download