Writing an Eclipse plug-in that uses native code via JNI
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…
- [1] The University of Manitoba has a good walk-through but it’s for Eclipse 2.1. In many ways this article is just an update of that.
- [2] What if you can’t find the Convert to C menu option?
- [3] How to mix Java and C code in a single project
- [4] More about how this stuff should work in future
- [5] Request for nature refactoring
- [6] CDT interworking with JDT
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.

December 18th, 2006 at 7:40 pm
And here’s an equivalent makefile that works under Carbide.
January 4th, 2007 at 10:31 am
[…] Previously I explained how to create a JNI plug-in for Eclipse, from Eclipse. […]
January 10th, 2007 at 6:28 pm
[…] I thought I had it all cracked when I managed to link to one of my DLLs from within an Eclipse plug-in. Today I wanted to do the same thing, with the only difference being that the DLL is a Microsoft one. […]
January 22nd, 2008 at 11:00 pm
I created a Java project in Eclipse referencing a DLL and everything ran properly. In Interface.java I declared the native functions, ie:
public native int ced_open_file(String filename);
….
static {
System.loadLibrary(”libparser.dll”);
}
Test.java contains the main program.
I moved the same files in a Plug-in project. I added libparser.dll to the root and added it to build.properties. I get the error:
java.lang.UnsatisfiedLinkError: myplugin/Interface.open_file
at myplugin.Interface.open_file(Ljava.lang.String;)I(Interface.java:???)
at myplugin.Test.main(Test.java:29)
I have also changed System.load to System.loadLibrary(exact path to dll) and added the path to the VM arguments using -Djava.library.path. I get the same error.
Have any suggestions to why it works as a Java Project but not as a plug-in?
January 23rd, 2008 at 12:28 pm
Hi, no specific answers. But it looks like it’s failing when it’s trying to call the DLL function rather than when it’s loading the DLL. Maybe you changed the package name or something else which affects the name of the symbol it needs to call?
Also from your code example, it is trying to call Interface.open_file but your native method is ced_open_file
January 24th, 2008 at 1:44 am
Yes, when I debug I fail when trying to call the DLL function not when loading. Someone suggested adding…
Bundle-NativeCode: libparser.dll;osname=win32;processor=x86
to the header of MANIFEST.MF. However, it didn’t make any difference when I ran my code. Have you used Bundle-NativeCode?
And yeah the code example difference was a typo.