First I was afraid, I was petrified. Kept thinking I could never live without a proper JNI reference manual by my side. But I spent so many nights thinking how to implement those native methods right. I grew strong, I learned how to carry on without a proper wrapper generator.
But now Swig is back, from a quite silent place. I just Googled in and found that it had reached Version 1.3. I should have closed that stupid JNI reference book. If I had known for just one second that Swig would be back to help me.
Even though Swig is a generic tool, compatible with a host of non-native languages, this post focuses on its Java interaction.
After having looked at that version I have changed my mind. Swig does provide some value - or at least does not make the native bridging less dynamic than raw JNI. A simple example of Swig with Java follows.
For Java, you can specify an interface file, which could be the regular C header for the native code, such as
// File: mathus.h
extern int fac(int arg);
This is done via the following command
swig -java -module Mathus mathus.h
which will create a few new files:
1. Mathus.java - a class ‘Mathus’ with wrapper methods for all the functions specified in ‘fac.h’ (i.e., only the ‘fac’ function…) These wrappers are very thin (and do not add much value, to be honest.)
2. MathusJNI.java - the Java side of the native implementation, which is nothing but a signature of the function and the keyword ‘native’. Note that Java client code should *not* use this class, but rather the aforementioned wrapper class.
3. mathus_wrap.c - ah, the JNI implementation in all its g(l)ory. Read it and weep. The reason for all the obfuscation is to handle all imaginable compilers.
Let us create an implementation of that advanced numerical function:
// mathus.c
int fac(int arg)
{
return arg == 0 ? 1 : arg*fac(arg-1);
}
“But that prohibits those neat last call optimization tricks of the compiler, you should use an accumulating parameter!”
Sit down, you computer science freak! This is not class, this is real life, with real stacks! And do not mention negative numbers!
Ok, so now when we have these five files, whereof Swig created three, we just have to create a DLL. Since we do not want to spend money on Microsoft tools, but rather choose to give our money to the Gates Foundation in a more direct manner, we use GCC. The MinGW port, to be exact. Just install it - because all serious developers need a GCC implementation on their machine. Ok, a version of Emacs along with a decent LaTeX installation might qualify as well.
You have to type (or, better yet, put in a makefile…) the following, after setting the variable JAVA_INCLUDE to point to the include directory of your Java JDK installation (which is usually %JDK_HOME%\include):
gcc -Wall -Wl,–kill-at -shared -o mathus.dll -I%JAVA_INCLUDE% -I%JAVA_INCLUDE%\win32 Mathus_wrap.c mathus.c
The “-Wall” is for our S&M needs. Yes, Mr. Compiler, I have been a bad boy! Spank those unused variables out of me!
Now you have a nice JNI DLL. In order to use it, you just have to make sure to load it explicitly before the class with the native method (MathusJNI) is first used.
For instance:
// File: MathusClient.java public MathusClient { public static void main(String[] args) { // Let us do something really intricate here: int arg = Integer.parseInt(args[0]); int facRes = Mathus.fac(arg); System.out.println(“fac(” + arg + “) = “ + facRes); } static { // Yep, let’s load that DLL and get it over with… System.loadLibrary(“mathus”); } }
Download this code: MathusClient.java
Just compile it and run. And, more importantly, enjoy! Your first Java app with some cojones.
DISCLAIMER: it is late and I am typing all this from memory, so there might be typos, although I doubt it. There probably was one in that doubtful sentence…