The Java Native Interface (JNI) is a standard mechanism for inter-operability between Java and native code, i.e., code written in non-portable system programming languages like C. Jamaica implements Version 1.2 of the Java Native Interface. Since JNI provides hundreds of routines, including support for JNI would pose too big an overhead on those applications that are not using it. This is why JNI support must be activated explicitly by giving setting the option -jni when using the builder.
Native code that is interfaced through the JNI interface is typically stored in shared libraries that are dynamically loaded by the virtual machine when the application uses native code. Since dynamically loading libraries is not possible on small embedded systems that don't provide a file system, a different approach is taken by Jamaica. Instead of loading a library, it is preferable to have the native code be part of the application itself, i.e., to link the native object code directly with the application.
The Jamaica Builder allows direct linking of native object code with the application through the option -object <file>. All object files containing native code have to be presented to the builder using this option in addition to the option -jni that enables the support for JNI.
To build an application that uses the native code on a target that requires manual linking, it might also be required to provide these object files to the linker, and it might even be required to provide a specific Jamaica JNI-object file that contains the JNI support. Here is a short example on the use of the Java Native Interface with Jamaica. We have a small application that does nothing but write a hardware register using a native method.The Java code might look like Figure JNITest.java:
Jamaica provides a handy little tool, jamaicah, which generates a C header file for us. Note that jamaicah operates on Java class files, so we have to create one first. For this example, we use SUN's javac, but jikes or any other java-to-bytecode compiler would be fine. Here, we generate Figure JNITest.h
> javac JNITest.java > jamaicah JNITest |
The native code is implemented in the following routine written in C. See Figure JNITest.c for an example. Note that the mangling of the Java name into a name for the C routine is defined in the JNI specification. In order to avoid typos, just copy the function declarations from the generated header file.
Figure JNITest.c. The C implementation of the native function JNITest.write_HW_Register
|
Now, we have to generate a C object file. We use gcc, the GNU compiler here. Any other C compiler should also be fine. Note that the include directory may be different on your system.
> gcc -I /usr/local/jamaica/target/linux-gnu-i686/include -c JNITest.c |
Finally, we can call the Jamaica Builder to generate a binary file which contains all necessary classes as well as our C object file JNITest.c. We have to tell the Builder explicitly that we need this object.
> jamaica -smart -object JNITest.o JNITest Jamaica Builder Tool + JNITest__.c + JNITest.makefile Classfile compaction gain: 92.59319% (378368 ==> 28025) gcc -O2 -Wall -g -O2 -o JNITest__.o -c JNITest__.c -DNDEBUG -DJAMAICA_SHORT_MODEL -I /usr/local/jamaica/target/linux-gnu-i686/include gcc -o JNITest JNITest.o JNITest__.o -L/usr/local/jamaica/target/linux-gnu-i686/lib -lX11 -L/usr/X11/lib -lpthread -lm -L/usr/lib -lm -lpthread -ljamaicas32 -lX11 -L/usr/X11/lib -lpthread -lm -L/usr/lib -lm -lpthread -ljamaicas32 /usr/bin/strip JNITest |
And the resulting application can be executed just like a normal builder Java application:
> ./JNITest Now we could write the value 65632 into memory address fc000008 Result: 65632 |