How to call a C/C++ function from Java

Java Native Interface (JNI), part of the Java platform, is an interface that enables communication between Java applications running on a Java Virtual Machine (JVM) and native applications or libraries written in other programming languages (e.g. C, C++).

JNI provides improved performance in some low-level tasks (e.g. Math.sqrt (double a)) and enables communication with hardware devices (Bluetooth, Wi-Fi, etc.). However, there is a disadvantage in the loss of platform independence, because such program uses the library compiled for specific operating system.

Java Native Interface - creating dynamic library and calling from Java

Java Native Interface – creating dynamic library and calling from Java

The figure above shows the implementation of a native library and its integration with Java. Example demonstrates how to call C library that prints the text “Hello World from C function!” from Java application. The entire implementation process can be summarized into several steps:

  1. Create a class that declares the native methods
    public class HelloWorld {
    
       static {
          // load the C-library
          System.loadLibrary("HelloWorld");
       }
    
       // declaration of native method
       private native void print();
    
       public static void main(String[] args) {
          new HelloWorld().print();
       }
    }
    
    • loadLibrary(String libname) method is used to load an external C-library, libname represents the path to the library.
    • Placing the call in a static initialization block ensures that the library is only loaded once per class. Static initialization block is executed immediately after the class is loaded into memory.
    • Keyword native is used to denote a native methods; the methods created in C-library, which will be called.
  2. Compile the Java program
    • In NetBeans IDE, right-click the project name and select Clean and Build from the context menu. Now the .class files will be created in the “build\classes” folder in the project directory.
    • Outside of IDE, use an external javac tool.
  3. Generate the header file
    • To generate a C-header file (.h) with a native function declaration use the javah tool (part of JDK, typically in C:\Program Files\Java\jdk\bin) on the Java .class file. Enter the file name without .class extension:
      javah -jni HelloWorld
    • Generated header file contains a declaration of C-function that is linked with the Java native method:
      JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);
  4. Write the C implementation of the native methods
    • In NetBeans IDE select New ProjectC/C++ Dynamic Library.
    • Created project must be linked with JNI libraries:
      • Right-click the project name and select Properties from the context menu.
      • On the Project Properties page, select C Compiler section, and in the Include Directories box type paths to JNI (typically C:/Program Files/Java/jdk/lib and C:/Program Files/Java/jdk/include/win32).
      • In the same section C Compiler, in the Additional Options box type:
        -Wl,--add-stdcall-alias -mno-cygwin -shared -m32 -Wall -pedantic
        • -Wl,–add-stdcall-alias passes option –add-stdcall-alias to the linker. The option sets alias for the function names without the addition of @nn.
        • -mno-cygwin ensures independence from cygwin.dll on Windows environment (when using cygwin gcc).
        • -shared option tells the compiler to generate a dynamic library instead of executable file.
        • -m32 option tells the compiler to create a 32b binary (required only when using 64b GCC and 32b JDK).
        • -Wall -pedantic ensures print of all warning messages and source code control to ANSI standards.
      • Copy the generated header file to the created project directory and link it to the project (right-click the Header Files node, select Add Existing Item from the context menu).
      • Implement methods, right-click the Source Files node, select New and then C Source File.
      • Edit the created file by typing the following code:
        #include <jni.h>
        #include <stdio.h>
        #include "HelloWorld.h"
        
        JNIEXPORT void JNICALL
        Java_HelloWorld_print(JNIEnv *env, jobject obj) {
            printf("Hello World from C function!\n");
        }
  5. Compile the dynamic library
    • Right-click the project name and select Clean and Build.
    • Now the dynamic library file (.dll for Windows, .so for Unix) will be created in the “dist” folder in the project directory.
  6. Run the program using the java runtime interpreter
    • Copy the generated library (.dll or .so) to the Java project directory or to the directory where executable file.
    • If library in another directory, must define the path in the loadLibrary(String libname) method.
    • Run the Java application and output prints the text “Hello World from C function!” as defined in C.

More information about JNI can be found in the book Java Native Interface: Programmer’s Guide and Specification.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>