How to fix UnsatisfiedLinkError in JNI
I have never had problems with JNI. In the few situations when I needed it, it just worked. But last week someone asked me for help with his problem. When I tried to reproduce it, I found out that it had spread even to my old JNI programs which worked until 2006!
When running a program that uses a native function the following error occured:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Test.dll: Can't find dependent libraries
It’s obviously a linker problem related to the generation of the .dll file. I have no idea why it occurs now and didn’t occur in the past. Different OS, compiler version, something like that? For some reason both the linker of Visual Studio and the linker of GCC started to think that is was a good idea to replace all method names by some arbitrary name which then cannot be found at runtime.
Fix for GCC
To fix that with GCC, the linker opion --add-stdcall-alias can be used.
gcc -Wl,--add-stdcall-alias -mno-cygwin -shared -I/cygdrive/c/Program\ Files/Java/jdk1.6.0_05/include -I/cygdrive/c/Program\ Files/Java/jdk1.6.0_05/include/win32 -o HelloWorld.dll HelloWorld.c
Fix for Visual C
For Microsoft Visual C Compiler it should theoretically be possible with a linker option as well.
Find out the correct linker option
First compile and link in the usual way that didn’t work. This will create the .dll file which results in the error we are talking about. Then use the dumpbin tool to list the procedure names:
dumpbin HelloWorld.dll /EXPORTS
You will find your procedure name, something like _Java_HelloWorld_print@8. Now try to guess what the name should be. My guess in this case would be Java_HelloWorld_print. This would result in the linker option /EXPORT:Java_HelloWorld_print=_Java_HelloWorld_print@8
Supply the linker option
- Use a
#pragma commentin the source file:#pragma comment(linker, "/EXPORT:Java_HelloWorld_print=_Java_HelloWorld_print@8")
OR
- Split into linking and compiling and provide the option to the linker in the command line, OR
- Supply it to the compiler at the end using
/link:cl -I"C:\Program Files\Java\jdk1.6.0_05\include" -I"c:\Program Files\java\jdk1.6.0_05\include\win32" -MD -LD HelloWorld.c -FeHelloWorld.dll /link /EXPORT:Java_HelloWorld_print=_Java_HelloWorld_print@8
Edit: According to user comments, the -MD option above is wrong and causes the problem described below. Do not use -MD! See MSDN for further information about the -MD option.
Option 3 is probably the easiest. After that dumpbin will show that now there is an additional procedure with the correct name:
dumpbin HelloWorld.dll /EXPORTS
I even compared it with the working .dll I created with GCC (see above), and it looks the same! But it doesn’t work, still getting the same error!
So, I searched a lot, but I found a solution that worked for me. Removing the -MD gives you this:
cl -Ic:\java\include -Ic:\java\include\win32 -LD HelloWorld.c -FeHelloWorld.dll
For me, it worked! For the rest, I can’t speak C++ and I don’t know why it happened.
Thanks Alexandra,
your insight will help many people! This post gets lots of hits every day :-)
Kai
I have a problem creating a simple Java Application that uses JNI to load a dll that prints the mesage “HelloWorld”.
The following stages were succesful:
1. Creating the HelloWorld.java file and compiling it.
2. Using javah -jni to produce HelloWorld.h (a C/C++ header file)
3. Coding the HelloWorld.c file and compiling it to get:
a) HelloWorld.exp, HelloWorld.dll, HelloWorld.lib, HelloWorld.obj
The stage where I am failing:
1. Running the Java program using: java HelloWorld at the command line produces the following error:
Exception in thread “main” java.lang.UnsatisfiedLinkError: HelloWorld.helloWorld
()V
at HelloWorld.helloWorld(Native Method)
at HelloWorld.main(HelloWorld.java:8)
C:\>
For compilation purposes I am using the Microsoft Visual C++ 2008 Express Edition’s command line utility
What could be the problem with my program
Thanks in anticipation of the best help you can offer
Hello,
is that all the error message you get? Delete the .dll, try again. When it is still the same message, then you know more about the problem. Otherwise you know more as well. Win-win.
Kai
Thanks Alexandra, your insight really works.
I got the same problem with Kai. I think it’s not about the procedure name. If you remove the “-MD” option when you link the C file, it can work.
Wow !!
Thanks so much.
This topic helped me getting started with Java -> JNI -> DLL.
Thanks
add option “-Wl,–kill-at”
`–kill-at’
Specifies that when `dlltool’ is creating the
exports file it should not append the string
`@ ‘. These numbers are called
ordinal numbers and they represent another
way of accessing the function in a DLL, other
than by name.
With this the problem will go away sure shot.
just need to build the helloworld.c following way
cl -I c:\Java\jdk1.6.0_01\include -I c:\Java\jdk1.6.0_01\include\win32 -LD HelloWorld.c -FeHelloWorld.dll
Not with -MD option. Java load library functions are not able to load because of -MD option. I think JNI documentations should be updated.
Exception in thread “main” java.lang.UnsatisfiedLinkError: sendechotohost
at NativePing.sendechotohost(Native Method)
at NativePing.getResultForTheHost(NativePing.java:517)
at NativePing.pingHost(NativePing.java:396)
at NativePing.pingHost(NativePing.java:422)
at NativePing.pingHost(NativePing.java:384)
at NativePing.main(NativePing.java:616)
In Linux I am getting this error. Can any one explain….
hello Franklin,
I’d say either the native binary is not found or it doesn’t contain what you need.
Did you compile it with gcc –add-stdcall-alias? Did you check out which functions the binary contains? Did it contain sendechotohost? Is it in the runtime PATH?