Apologies for the non-techy readers of this blog. I’ve got to post this techie stuff somewhere - I’ll eventually probably create a library of technical articles somewhere on this website.
Eclipse’s modularity is successful partly because it contains great tools for creating Eclipse plug-ins. But those tools break down when you want to create a plug-in that includes native code. Of course, you want to avoid that in the first place since it won’t be cross-platform… but sometimes you have to.
Here’s a recipe for creating a native plug-in on Eclipse 3.2. There might be better ways!
First of all, reference sources…
First, if you’re not familiar with JNI, read the introduction in [1] - it’s much more thorough than this. This article just talks about how to do it in Eclipse.
Step One - create your plug-in project
Create a standard Eclipse Java plug-in project.


I used the “Hello, world” template to create a plug-in which will create a menu command. By default, it prints a string: “Hello, we’ll soon be replaced!”… our intention is to replace that with a string generated by native code.
Check that your plug-in builds and runs (Run As Eclipse Application), and that the menu option appears as intended and does what you wanted.

Step Two - making Java code changes to call a native API
Here’s where you write your JNI code in the Java. Refer to [1] if you don’t know enough about JNI. I’m adding:
public native String getNativeMessage();
static {
System.loadLibrary("testjniplugin");
}
and of course changing run to
public void run(IAction action) {
String message;
try {
message = getNativeMessage();
} catch (Throwable e) {
message = e.toString();
}
MessageDialog.openInformation(
window.getShell(),
"MyProjectWithJNI Plug-in",
message);
}
Step Three - watch it break
Now try running the Eclipse application. Impressively, Eclipse works fine, and even gives you a nice error message if you choose the offending action.
Step Three - Add C Nature to the Project
Eclipse projects have one or more “natures” - for example, Java or C++. We want to add a C nature to the project. See [4] and [5] for information about how this should work in future, but for now, it’s a little fiddly.
- Choose Window -> Open Perspective -> Other
- Select C/C++
- Right-click on the project folder
- Under New, select Convert to a C/C++ Make Project
- Choose C

If you choose Build Project, you’ll find that nothing much happens. You’ll get an error message:
make -k all
make: *** No rule to make target `all'.
So we have to tinker with the build files.
Step Four - add a Makefile with javah
- In the root of the project, select New -> File.
- Entitle it Makefile.
- In the Makefile, add the following lines:
all : myprojectwithjni_actions_SampleAction.h
myprojectwithjni_actions_SampleAction.h : bin/myprojectwithjni/actions/SampleAction.class
javah -classpath bin -jni myprojectwithjni.actions.SampleAction
clean :
-del myprojectwithjni_actions_SampleAction.h
For those new to JNI, javah is a command which takes a Java .class file and creates a C .h file representing the different native functions therein which need to be implemented.
Now right-click on the project and select Build Project. You’ll find that a new file appears in the project view: myprojectwithjni_actions_SampleAction.h. The important line of that file is the function you must implement in your DLL:
JNIEXPORT jstring JNICALL Java_myprojectwithjni_actions_SampleAction_getNativeMessage
(JNIEnv *, jobject);
Note that we’re being passed a JNIEnv and a jobject - the latter being the SampleAction class on which our method is being called - and returning a jstring.
Step Five - Add a C (or C++) file that implements it
We now add our C code to the project. First choose New -> Source folder, and name it nativesrc. Secondly, add a new source file - SampleAction.c - within that folder. Put in:
#include
#include “myprojectwithjni_actions_SampleAction.h”
#include
JNIEXPORT jstring JNICALL Java_myprojectwithjni_actions_SampleAction_getNativeMessage
(JNIEnv * env, jobject obj)
{
return (*env)->NewStringUTF(env, “Here’s a native string in UTF8!”);
}
and of course the Makefile will need some changes:
all : testjniplugin.jnilib
testjniplugin.jnilib : nativesrc/SampleAction.c myprojectwithjni_actions_SampleAction.h
gcc -I . -I /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/headers -c
-o testjniplugin.o nativesrc/SampleAction.c
libtool -dynamic -o libtestjniplugin.jnilib testjniplugin.o
myprojectwithjni_actions_SampleAction.h : bin/myprojectwithjni/actions/SampleAction.class
javah -classpath bin -jni myprojectwithjni.actions.SampleAction
clean :
-del myprojectwithjni_actions_SampleAction.h
-del testjniplugin.jnilib
(Note the eventual library is getting called libtestjniplugin.jnilib. That’s under MacOS X. The filenames and commands will be somewhat different under Windows. See [1] for the details).
You should see the .jnilib DLL appear in the project:

Step Six - Run
That should be all you need. Now run the project and try the menu item in the spawned Eclipse. You should see it working!

If it still doesn’t work, you can try to manually add the DLL to the library search path like this.
Remaining unknowns
- Whether there’s a way to use Managed make, or Ant buildfiles, to build the native stuff. [3] suggests so, with some hackery. And whether there’s any way to make things cross-platform by doing that.
- Whether you can arrange for C++ code to hit breakpoints while you’re running your DLL in a spawned Eclipse. Doug at [6] suggests not, for now.