| < Day Day Up > |
|
C++ native code can be called from a Java program. This is accomplished using the Java Native Interface (JNI). With Java and JNI you write a Java program that dynamically loads a native library that contains one or more native methods declared in the Java class. The dynamic link library can be created using C++. The next section describes the process in detail and then gives both a Win32 and Macintosh OSX example.
This section lists the steps required to create a JNI C++ program. The steps are further illustrated in figure 18-20.
Step 1 - Create a Java source file that declares a class with one or more native methods. In addition to any native methods this class requires it also must also load the native dynamic library module using the System.loadLibrary() function.
Step 2 - Compile the Java source file to create a .class file.
Step 3 - Use the javah compiler with the -jni switch to automatically create a header file for use in your C++ program.
Step 4 - Create a C++ source file that implements the native method.
Step 5 - Compile the C++ source file to create a dynamic link library that exports the native method.
Step 6 - Run the Java program using the java virtual machine and do a victory dance!
Figure 18-20: Steps to Create a Java Native Interface (JNI) Program
Everything goes smooth up until around step 6. Success here depends on what operating system you are running since the name of the library file the java virtual machine is looking for is - you guessed it - implementation dependent. Consult the Java JNI documentation to learn how to properly form dynamic library names in your computing environment. The next section provides a complete JNI example targeting the Win32 environment.
In this section I will show you how to create a complete JNI program that targets the Win32 platform. This example will entail creating a Java class named SayHi. The SayHi class will declare a native method named sayHi(). The sayHi() method will be implemented in C++ and saved in a Win32 dynamic link library (DLL). To call the sayHi() method the SayHi class must first load the DLL. These steps are described in detail below.
Start your JNI project by creating a Java source file that declares one or more native methods. Example 18.11 gives the source code for a Java class named SayHi.
Listing 18.11: SayHi.java
1 public class SayHi{ 2 3 public native void sayHi(); 4 5 public void loadLibrary(String lib_name){ 6 System.loadLibrary(lib_name); 7 } 8 9 public static void main(String args[]){ 10 SayHi sh = new SayHi(); 11 sh.loadLibrary(args[0]); 12 sh.sayHi(); 13 } 14 }
On line 3 the SayHi class declares a native method named sayHi() that is public, returns void, and takes no function arguments. Note that this is only a function declaration as opposed to an ordinary Java method which normally combines both the function declaration and definition within the class body.
On line 5 a function named loadLibrary() is defined. The loadLibrary() function will take a String argument that represents the name of the DLL the SayHi class must load before calling the sayHi() function. The loadLibrary() function then calls the System.loadLibrary() function using the lib_name parameter. Using a class instance function to load the dynamic library allows the overhead associated with loading the library to be deferred until it is actually needed.
The main() function begins on line 9. A new SayHi object is created on line 10. Next, the loadLibrary() function is called using the library string name contained in arg[0]. Finally, the sayHi() function is called on line 12.
Use the Java compiler to compile the SayHi.java file. The Java compiler is invoked using the javac command as shown in figure 18-21.
Figure 18-21: Compiling SayHi.java
Compiling the SayHi.java file results in a Java class file names SayHi.class as shown in figure 18-22.
Figure 18-22: Compiling SayHi.java Results in SayHi.class
To create a C++ implementation of a Java native method you must have a header file that declares the C++ version of the method. The Java platform supplies a command line tool named javah that can be used to automatically create these header files. The javah tool requires a Java class file. It automatically assumes the .class file extension. Figure 18-23 shows the javah tool being used to create the SayHi.h header file.
Figure 18-23: Using javah to Create the SayHi.h Header File
Figure 18-24 shows the results of creating the SayHi.h header file with the javah command line tool.
Figure 18-24: Results of Creating SayHi.h Using javah Command Line Tool
Example 18.12 shows the contents of the SayHi.h header file.
Listing 18.12: SayHi.h
1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include <jni.h> 3 /* Header for class SayHi */ 4 5 #ifndef _Included_SayHi 6 #define _Included_SayHi 7 #ifdef __cplusplus 8 extern "C" { 9 #endif 10 /* 11 * Class: SayHi 12 * Method: sayHi 13 * Signature: ()V 14 */ 15 JNIEXPORT void JNICALL Java_SayHi_sayHi 16 (JNIEnv *, jobject); 17 18 #ifdef __cplusplus 19 } 20 #endif 21 #endif
The actual native function declaration appears on lines 15 and 16. For a complete discussion on the purpose and use of the JNIEnv* and jobject parameters refer to the JNI references listed at the end of the chapter.
Now, with the header file generated you can create the SayHi() function C++ implementation file.
Example 18.13 shows the source code for the sayhi.cpp file.
Listing 18.13: sayhi.cpp
1 #include "jni.h" 2 #include "SayHi.h" 3 #include <iostream> 4 using namespace std; 5 6 JNIEXPORT void JNICALL Java_SayHi_sayHi (JNIEnv * env, jobject jo){ 7 8 cout<<"C++ SayHi() function working fine!"<<endl; 9 }
The sayhi.cpp file needs to include the jni.h and the freshly-generated SayHi.h header files in addition to the iostream header file. With the sayhi.cpp file in hand you can now create a DLL.
To create the Win32 DLL I will use Metrowerks CodeWarrior Release 5 and start with an empty project. I will then add the sayhi.cpp file and any libraries needed to create the DLL.
Figure 18-25 shows a blank CodeWarrior project window named JNI_Test. Figure 18-26 shows the sayhi.cpp file added to the blank project.
Figure 18-25: Blank CodeWarrior Project
Figure 18-26: sayhi.cpp Added to Blank Project
To generate a Win32 DLL using Metrowerks CodeWarrior you must add several important libraries. Figure 18- 27 shows the blank project window after adding the necessary libraries.
Figure 18-27: Blank Project Window Showing Added Library Files
Almost there. Before generating the DLL you must set some target settings. Figure 18-28 shows the target settings window with the necessary settings.
Figure 18-28: Target Settings Widow
Notice in the Target Settings window the Project Type is set to Dynamic Link Library (DLL) and the File Name is set to SayHi.dll.
When the necessary target settings are completed you can make the project to generate the SayHi.dll file. Figure 18-29 shows a directory listing after compiling the SayHi project.
Figure 18-29: Directory Listing Showing SayHi.dll
Once you have generated the SayHi.dll file successfully you can run the SayHi Java application. The name of the SayHi dynamic link library must be supplied on the command line when the SayHi Java application is run. The command line to execute the SayHi program looks like this:
java SayHi SayHi
Notice the name of the dynamic link library is just SayHi and not SayHi.dll. The System.loadLibrary() function will complete the library name by appending the .dll extension to the library name you supply. Figure 18-30 shows the results of running the SayHi Java application.
Figure 18-30: Results of Running the SayHi Java Application
In this section I will show you how to create the Macintosh OSX version of the same SayHi JNI program as shown in the previous section. The steps are the same as those listed in the Win32 example with two major exceptions. 1) The name of the dynamic link library will be different and, 2) the development environment used to create the dynamic link library will be different.
The same SayHi.java file used in the previous section will be used in this example. Refer to example 18.11 for the SayHi.java source code.
The Macintosh™ OSX operating system comes with a set of developer tools that includes the Java platform for OSX. The command line tools are the same for OSX as they are for Microsoft Windows™. Compile the SayHi.java file to produce the SayHi.class file.
Use the javah command line tool to create the SayHi.h header file. This file should look exactly like the SayHi.h file created using the Win32 version of javah.
The same C++ source file sayhi.cpp used in the Win32 example is used here as well. Refer to example 18.13 for the source code listing of sayhi.cpp.
OK, here is where things go a little differently. I will use the GNU C++ compiler to create the OSX version of the dynamic link library. The GNU C++ compiler comes with Macintosh OSX but you might have to install it separately. If you have not installed the OSX developer tools you should do so now.
To create the dynamic link library with the GNU C++ compiler use the following command line:
g++ -I <java include file path> -dynamiclib -o <output file name><C++ source file to compile>
The -I switch tells the GNU C++ compiler where to find include files. You will have to use this compiler switch to tell the compiler where to find the jni.h header file as it will most likely not be located in the environment's normal include path.
The -dynamiclib switch tells the compiler to produce a dynamic link library. The -o switch tells the compiler what to name the output file. The name of the OSX version of the dynamic link library should be lib<lib_name>.jnilib. In other word, the Java System.loadLibrary() function, when run in the OSX environment, will take the name of the library (SayHi) and prefix it with lib and suffix it with .jnilib to form the complete library name. Therefore, it will look for a library file named libSayHi.jnilib. You must instruct the GNU compiler to produce a dynamic link library file named libSayHi.jnilib.
Finally, tell the GNU compiler the name of the C++ file to compile. Figure 18-31 shows the GNU C++ complier being invoked from a Macintosh™ OSX terminal window.
Figure 18-31: Compiling sayhi.cpp Using g++ to Generate an OSX Dynamic Link Library
Figure 18-32 shows the directory listing that includes the libSayHi.jnilib dynamic link library file.
Figure 18-32: Directory Listing Showing libSayHi.jnilib File
All that is left to do is run the SayHi Java program. This is done in exactly the same fashion as the Win32 example. Use the java command line tool giving the name of the SayHi class and the name of the SayHi dynamic link library. Figure 18-33 shows the results of running the Java SayHi program.
Figure 18-33: Results of Running SayHi Java Program in an OSX Terminal Window
There is a certain amount of overhead involved with making a native function call from a Java program. If you are writing a native function with the intention of calling it frequently, say, from the body of an often-repeated loop, a native method may not be the optimum solution, especially if the function is small and takes only a fraction of the time to execute vs. the time it takes to make the function call. If, however, the function does something significant and is called infrequently, then JNI may be the way to go.
C++ can be used to write functions that target specific hardware platforms. These native functions can be called from a Java program using the Java Native Interface. Most of the steps involved in creating a JNI program are portable across computing platforms with the exception of how the native dynamic link library is created and how it is named.
| < Day Day Up > |
|