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

Java Native Interface (JNI), part of the Java platform, is an interface that enables the 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 losing platform independence because such a 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. The 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. The static initialization block is executed immediately after the class is loaded into memory.
    • The keyword native is used to denote 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. 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
    • The 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 the C Compiler section, and type paths to JNI in the Include Directories box (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 the Windows environment (when using Cygwin gcc).
        • -shared option tells the compiler to generate a dynamic library instead of an 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.
    • 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 the executable file is.
    • If the library is in another directory, the path must be defined in the loadLibrary(String libname) method.
    • Run the Java application, and the 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 *