[GCS] – Java Native Interface for beginner.


Set up the Environment

At first, you need to have the environment for running JNI code.

To compile C/C++ source code. You have to set up MingW or Cygwin. You can install it from Y:\Apps\Free\ in local computer or you can down load from Internet.

To complile Java source code, you need to set up JDK (recommendate jdk 32 bit ) from website: http://www.oracle.com/technetwork/java/javase/downloads/index.html

For more convenient, you should download Eclipse: http://www.eclipse.org/downloads/  then choose  Eclipse IDE for Java Developers. (recommendate Eclipse 32 bit ) After you setup Eclipse, go to help -> Install a new software -> enter: Kepler – http://download.eclipse.org/releases/kepler  -> wait a minute and extend Programing Language -> tick on C/C++ Develope tool. -> finish.

After that, you have to add Environment to the System Environment. Right click at MyComputer -> Propertise -> Advance System setting -> Environment Variable -> Add to path the link: C:\Program Files (x86)\Java\jdk1.7.0_25\bin;C:\Program Files (x86)\Java\jre7\bin;C:\MinGW\bin

That so, now you have the Environment to build and run the JNI project. Let try the simple HelloJNI project below.

Attempt simple project

Step 1: Create a Java Project

Create a new Java project (says HelloJNI), and the following Java class “HelloJNI.java“:

public class HelloJNI {
   static {
      System.loadLibrary("hello"); // hello.dll (Windows) or libhello.so (Unixes)
   }
   private native void sayHello();

   public static void main(String[] args) {
      new HelloJNI().sayHello();  // invoke the native method
   }
}
Step 2: Convert the Java Project to C/C++ Makefile Project

Right-click on the “HelloJNI” Java project ⇒ New ⇒ Other… ⇒ Convert to a C/C++ Project (Adds C/C++ Nature) ⇒ Next.

The “Convert to a C/C++ Project” dialog appears. In “Project type”, select “Makefile Project” ⇒ In “Toolchains”, select “MinGW GCC” ⇒ Finish.

Now, you can run this project as a Java as well as C/C++ project.

Step 3: Generate C/C++ Header File

Create a directroy called “jni” under the project to keep all the C/C++ codes, by right-click on the project ⇒ New ⇒ Folder ⇒ In “Folder name”, enter “jni“.

Create a “makefile” under the “jni” directory, by right-click on the “jni” folder ⇒ new ⇒ File ⇒ In “File name”, enter “makefile” ⇒ Enter the following codes. Take note that you need to use tab (instead of spaces) for the indent.

# Define a variable for classpath
CLASS_PATH = ../bin

# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)

# $* matches the target filename without the extension
HelloJNI.h : HelloJNI.class
	javah -classpath $(CLASS_PATH) $*

This makefile create a target “HelloJNI.h“, which has a dependency “HelloJNI.class“, and invokes the javah utiltiy on HelloJNI.class (under -classpath) to build the target header file.

Right-click on the makefile ⇒ Make Targets ⇒ Create ⇒ In “Target Name”, enter “HelloJNI.h“.

Run the makefile for the target “HelloJNI.h“, by right-click on the makefile ⇒ Make Targets ⇒ Build ⇒ Select the target “HelloJNI.h” ⇒ Build. The header file “HelloJNI.h” shall be generated in the “jni” directory. Refresh (F5) if necessary. The outputs are:

make HelloJNI.h 
javah -classpath ../bin HelloJNI

Read “GCC and Make” for details about makefile.

Alternatively, you could also use the CMD shell to run the make file:

// change directory to the directory containing makefile
> make HelloJNI.h

You can even use the CMD shell to run the javah:

> javah -classpath ../bin HelloJNI
Step 4: C Implementation – HelloJNI.c

Create a C program called “HelloJNI.c“, by right-click on the “jni” folder ⇒ New ⇒ Source file ⇒ In “Source file”, enter “HelloJNI.c“. Enter the following codes:

#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"

JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
   printf("Hello World!\n");
   return;
}

Modify the “makefile” as follows to generate the shared library “hello.dll“. (Again, use tab to indent the lines.)

# Define a variable for classpath
CLASS_PATH = ../bin

# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)

all : hello.dll

# $@ matches the target, $< matches the first dependancy
hello.dll : HelloJNI.o gcc -Wl,--add-stdcall-alias -shared -o $@ $<

# $@ matches the target, $< matches the first dependancy
HelloJNI.o : HelloJNI.c HelloJNI.h gcc -c $< -o $@

# $* matches the target filename without the extension
HelloJNI.h : HelloJNI.class
	javah -classpath $(CLASS_PATH) $*

clean : rm HelloJNI.h HelloJNI.o hello.dll

Right-click on the “makefile” ⇒ Make Targets ⇒ Create ⇒ In “Target Name”, enter “all“. Repeat to create a target “clean“.

Run the makefile for the target “all“, by right-click on the makefile ⇒ Make Targets ⇒ Build ⇒ Select the target “all” ⇒ Build. The outputs are:

make all
javah -classpath ../bin HelloJNI
gcc -I"D:\bin\jdk1.7\include" -I"D:\bin\jdk1.7\include\win32" -c HelloJNI.c -o HelloJNI.o
gcc -Wl,--add-stdcall-alias -shared -o hello.dll HelloJNI.o

The shared library “hello.dll” shall have been created in “jni” directory.

Step 5: Run the Java JNI Program

You can run the Java JNI program HelloJNI. However, you need to provide the library path to the “hello.dll“. This can be done via VM argument -Djava.library.path. Right-click on the project ⇒ Run As ⇒ Run Configurations ⇒ Select “Java Application” ⇒ In “Main” tab, enter the main class “HelloJNI” ⇒ In “Arguments”, “VM Arguments”, enter “-Djava.library.path=jni” ⇒ Run.

You shall see the output “Hello World!” displayed on the console.

Some of error can meet

– First, if your computer is operating 64 bit. So, you may set up JDK 64 bit and Eclipse 64 bit. But, when make file to create dynamic library ( .dll file), the .dll file is 32-bit .dll. Then, it can’t load on a AMD 64-bit platform. It always give the error: “Can’t load IA 32-bit .dll on a AMD 64-bit platform. This error is easy to fix by remove all of JDK and Eclipse 64 bit, then set up JDK and Eclipse 32 bit. It’s worked.

– Second, It’s not a good idea if setting Toolchain “MingW” and “Cygwin” together, because the compiler might not to know where to load the library.

– Third, It has two way to build a source code. Build for application and build for library. Build for application need main() function, but when build JNI source file ( .c ) the source file doesn’t have main() ( because it’s just implemented method, and main() is belong .java file ). Therefore, it’s always give error: “/mingw/lib/libmingw32.a(main.o):main.c:(.text+0x106): undefined reference to `WinMain@16”. The error occur in linker process. To fix this error by go to the “Project -> Properties -> C/C++ Build -> Setting -> MingW C/C++ setting -> tick to the checkbox “Shared”.

Source code

This session contain some of basic JNI code. You can download and run to understand some basic concept in JNI. Such as: Hello World, Access String, Access Array, Access static and non static Field , Call Method and Static method, Thread with JNI and a small project caculate quadratic equation.

Basic JNI project.zip

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: