Eclipse: Hello World in Java Native Interface on Windows
15 January 2012
Rationale
To use a single workspace within a single installation of Eclipse to develop a project which consists of source files written in both C and Java with calls between them – on a Windows x86 based development machine. The rationale being to increase the ease of development and automate certain parts of the build processes.
Software Components used
Cygwin OR MinGW for compiling C code
JDK for compiling Java code
Eclipse as the IDE
JDT and CDT plugins for Eclipse
Installation Instructions
Make sure you have the following installed. If not, then follow this particular order
Install Java Development Kit (JDK) Standard Edition (SE) for Windows 32bit
http://www.oracle.com/technetwork/java/javase/downloads/index.html
Install Eclipse IDE for Java Developers for Windows 32bit
(This includes JDT)
Eclipse Eclipse CDT (C/C++ Development Tooling) Plugin
Install EITHER Cygwin
(During Installation, select the “Devel” option in the Select Packages Window)
OR MinGW
BUT NOT BOTH
Java Code
Start Eclipse. Preferably create a new workspace called WorkSpaceEclipseJNI
From the menu select File>New>Java Project
Enter Project Name as 01Java_HelloWorld
Click Next >
Click Finish
In the Package Explorer expand 01Java_HelloWorld
Right click src folder and select New>Package
Enter Name as com.lithiumhead.jni
Click Finish
In the Package Explorer under 01Java_HelloWorld > src right click com.lithiumhead.jni and select New>Class
Enter Name as HelloWorld
Click Finish
Paste the following code into HelloWorld.java
package com.lithiumhead.jni;
class HelloWorld {
public native void sayHello();
static {
System.loadLibrary("HelloWorld");
}
public static void main(String[] args) {
HelloWorld h = new HelloWorld();
h.sayHello();
}
}
From the menu select Run>External Tools>External Tools Configurations…
Highlight Program in the list in the left pane
Press the New button
Enter Name as javah - C Header and Stub File Generator
For the Location browse to locate javah.exe in the JDK installation folder
(will be something like C:\Program Files\Java\jdk1.7.0\bin\javah.exe)
Enter Working Directory as: ${project_loc}/bin/
Enter Arguments as -jni ${java_type_name}
Click Apply
Switch to the Common tab
Select the checkbox next to External Tools under Display in favourites menu
Click Apply
Click Close
Deselect Build Automatically from Project Menu
In the Package Explorer right click 01Java_HelloWorld and select Build Project
In the Package Explorer highlight HelloWorld.java
From the menu select Run>External Tools>1 javah - C Header and Stub File Generator
(This will generate the header file for the C code com_lithiumhead_jni_HelloWorld.h placed in the bin folder of 01Java_HelloWorld Java Project.)
C Code
From the menu select File>New>Project…
Expand C/C++
Highlight C Project
Click Next >
Under Project type, expand Shared Library
Highlight Empty Project
Under Toolchains select Cygwin GCC (or MinGW GCC)
Enter Project name as 01C_HelloWorld
Press Next >
Uncheck Debug. Let only Release remain checked.
Click Finish
If asked for switching Perspective to C/C++, check Remember my decision and click Yes
In the Project Explorer right click 01C_HelloWorld and select New>Source File
Enter Source file as com_lithiumhead_jni_HelloWorld.c
Click Finish
Paste the following code in com_lithiumhead_jni_HelloWorld.c
#include <jni.h>
#include "..\01Java_HelloWorld\bin\com_lithiumhead_jni_HelloWorld.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_com_lithiumhead_jni_HelloWorld_sayHello(JNIEnv *env, jobject obj)
{
printf("Hello world!\n");
return;
}
Press Ctrl+S to save the C code
In the Project Explorer highlight 01C_HelloWorld
Press Alt+Enter to open the Properties for the project
Expand C/C++ Build
Highlight Settings
Highlight Includes from the list within the Tool Settings tab on the right side
Click Add…
Click File System…
Browse to the include folder in the JDK installation folder and click OK
(must be something like C:\Program Files\Java\jdk1.7.0\include)
Click OK
Click Add… again
Click File System… again
Browse to the include\win32 folder in the JDK installation folder and click OK
(must be something like C:\Program Files\Java\jdk1.7.0\include\win32)
Click OK
Highlight Miscellaneous under Cygwin C Linker (or MinGW C Linker) from the list
On the right side, enter Linker flags as -mno-cygwin -Wl,--add-stdcall-alias
(or just -Wl,--add-stdcall-alias in case of MinGW)
Click Apply
Switch to the Build Artifact tab
Delete the text for Artifact name and type in HelloWorld
Delete the text for Output prefix and keep it empty
Click OK
Right click 01C_HelloWorld in Project Explorer and select Build Project
(this will compile the project)
Running it
Switch to Java Perspective by selecting from the menu Window>Open Perspective>Other , select Java (default) and click OK
In the Package Explorer highlight 01Java_HelloWorld
Select Run>Run As>Java Application
This will create a default run configuration called HelloWorld for the project but at the same time throw up an error as observed in the Console View. This is because the Java Virtual Machine does not yet know the path of the DLL file generated from the C Code.
From the menu select Run>Run Configurations…
From the list within the left pane highlight HelloWorld under Java Application
On the right side, switch to Arguments tab
Enter VM arguments as
-Djava.library.path="${workspace_loc}\01C_HelloWorld\Release"
Click Close
In the Package Explorer highlight 01Java_HelloWorld
Select Run>Run As>Java Application
Observe the output in the Console View
References
Using Cygwin To Develop Windows JNI Methods
by David Caldwell
Using The Java Native Interface
by Christopher Batty
The Java Native Interface Programmer's Guide and Specification - Getting Started
-mno-cygwin -- Building Mingw executables using Cygwin
by Mumit Khan
MinGW’s Wikipedia Entry
Important points to note:
“However, because GCC does not supply its own C runtime library, MinGW's C compiler targets Microsoft's old Visual C runtime library, MSVCRT, which was released in 1998 and therefore does not include support for C99 features (let alone all of C89); while targeting MSVCRT yields programs that are as native as possible, the lack of support for C99 has caused porting problems, particularly where printf-style conversion specifiers are concerned.”
“MinGW forked from version 1.3.3 of Cygwin. Although both Cygwin and MinGW can be used to port Unix software to Windows, they have different approaches: Cygwin aims to provide a complete POSIX layer that provides emulations of several system calls and libraries that exist on Linux, Unix, and the BSD variants. The POSIX layer runs on top of Windows, sacrificing performance where necessary for compatibility. Accordingly, this approach requires Win32 programs written with Cygwin to run on top of a copylefted compatibility library that must be distributed with the program, along with the program's source code. MinGW aims to provide native functionality and performance via direct Windows API calls. Unlike Cygwin, MinGW does not require a compatibility layer DLL and thus programs do not need to be distributed with source code.”)