aaron-kelley.net

My little corner of the Internet

Getting Started with JNI and C++ under Windows

This is a step-by-step guide to getting started at using JNI with C++ under Windows.

JNI is pretty much a method to call C/C++ functions from a Java application. (Actually, calling native code written in other languages, including assembly, is supported as well, but here I am focusing on C++.) This guide should give you all you need to know to get JNI working quickly.

The JNI documentation for Java 1.6 is located here. The JNI 6.0 Specification is a good place to look, in fact, you’re going to read some of that to know how to call Java functions from C/C++, which Java types correspond to which C/C++ types, and so on. What the spec lacks is concrete information on how to get JNI working. In Chapter 2, they discuss how to name your C function and give some sample code. I could not get this to work, so I went off looking for better examples elsewhere.

Anyway, here’s what you do.

First, you must create a Java class with prototypes for the native functions that you want to use. You declare a function native just by including the keyword ‘native’ in its declaration, for instance, ‘static native double f();‘ is a static function that takes no parameters and returns a double. Note that you just end the function declaration with a semi-colon, you do not write any code for the function here.

This class may contain any other Java code that you like.

Next, you generate a header file using the native function declarations in your Java class. The JDK includes a program called javah that does this for you. If you have a class named MyClass, then open a command prompt and go to the directory containing MyClass.class and run the command javah MyClass. This will generate MyClass.h.

Now, you must create a .cpp file and implement at a minimum all of the functions declared in MyClass.h, and compile the results to a DLL. For information on how to do this with Microsoft Visual C++ 2005 Express Edition, see my previous post. I also have had success using gcc with Cygwin, see below.* Your .cpp file should include the .h file that was generated. You may link this code to whatever other C++ code you like (I am writing a JNI wrapper for an existing C++ library).

Note that when you compile this, it’s going to be looking for files in the JDK’s include folder. You’ll need to make sure that you add this to your include path. For instance, for me, I had to add “C:\Program Files (x86)\Java\jdk1.6.0_02\include” and “C:\Program Files (x86)\Java\jdk1.6.0_02\include\win32″ to the include path. These paths should be similar for you. (For information in how to do this in Microsoft Visual C++ 2005/2008, see below.**)

Now that you have your DLL, you’re ready to actually call these functions from Java. You must load your library from Java. This is done by calling the System.loadLibrary() function in Java. The line System.loadLibrary("MyClass"); will try to load MyClass.dll, looking for it in the current working directory and all directories in the system path. (You may also use System.load(); and provide a full path to the file, using ‘/’ instead of ‘\’ to mark directories, for example, System.load("c:/MyClass.dll");.)

As long as you call System.loadLibrary() before you make any native calls, and your DLL is in the right place, and you named all of the native C++ functions correctly (which should be easy, since that’s done for you in the generated .h file), it should be working now. If you get an UnsatisfiedLinkError exception when you make a native call, check to make sure that your C++ function header matches what was generated in the .h file. If you get it when calling System.loadLibrary(), check to make sure that your DLL is in the right place.

* I’m assuming you’re already familiar with gcc and Cygwin. To compile a DLL with gcc running under Cygwin, first use the command gcc -c MyClass.c to generate an object file, and then gcc -mno-cygwin -shared -Wl,--kill-at -o MyClass.dll MyClass.o to generate the DLL. The -mno-cygwin switch makes sure that the DLL generated is not dependent on the Cygwin runtime (i.e., you won’t have to have Cygwin installed to run code out of it). Similar compilation methods should work with g++, I haven’t tried it yet though. (source)

** In Visual C++ 2005/2008, go to “Tools -> Options”, then expand “Projects and Solutions” and select “VC++ Directories.” Click on the drop-down menu under “Show directories for:” and choose “Include files.” You can add include directories here, I had to add “C:\Program Files (x86)\Java\jdk1.6.0_02\include” and “C:\Program Files (x86)\Java\jdk1.6.0_02\include\win32″.

Tags: , ,

Comments are closed.