I'm having trouble loading a statically compiled library from Java using System.loadLibrary("") but I can load it as a dynamically compiled library (when I build it that way) just fine. I'm using JDK 8 and my understanding is it can load static libraries via System.loadLibrary("") if you provide a JNI_OnLoad_L in the *.cpp and *.h files.
My kdu_jni.h has:
extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *, void *);
My kdu_jni.cpp has:
JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *vm, void *reserved)
{
return JNI_VERSION_1_8;
}
I have the libkdu_jni.a file in my java.library.path directory when I try to run with the compiled version. It's working fine with a libkdu_jni.so file in that same directory when I try to load it dynamically. When trying with the static file (libkdu_jni.a), I get:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no kdu_jni in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
I've taken out the .so file before trying to load the .a file.
I'm not sure what I'm doing wrong. I don't think it's even seeing the libkdu_jni.a file's JNI_OnLoad_kdu_1jni() because I put an exception in there and I don't see that getting thrown. I've tried several iterations on that name: JNI_OnLoad_kdu_jni(), JNI_OnLoad_kdu_1jni(), JNI_OnLoad(), etc.
Any ideas?
my understanding is it can load static libraries via System.loadLibrary("") if you provide a JNI_OnLoad_L in the *.cpp and *.h files.
Your understanding is incorrect. You can't load a .a file dynamically. It isn't executable in any way shape or form:
infra-library references are not resolved
references outside the library are not resolved either: for example, to the C library.
The link step is essential, and the JVM doesn't do it for you. What you have read applies to libraries statically linked into the JVM.
I suggest you try JNI_OnLoad_kdu_jni as the function name. If that doesn't work, it might not work with library names that contain an underscore.
--- Original post follows ---
Prior to Java 8, only shared object libraries were supported.
This means that to know if the static library is Java 8, a new function must be implemented in the library.
JNI_OnLoad_libname must return a value of JNI_VERSION_1_8 or higher.
I'm guessing since your code works dynamically, but not staticly, perhaps this function is not present. The portion of JEP 178 below lead me to believe this:
The specifications of the java.lang.System.loadLibrary and
java.lang.Runtime.loadLibrary methods will be revised to read:
Loads the native library specified by the libname argument. The libname must not contain any platform-specific prefix, file extension,
or path.
If a native library called libname is statically linked with the VM, then the JNI_OnLoad_libname function exported by the
library is invoked. See the JNI Specification for more details.
Otherwise, the libname is loaded from a system library location and mapped to a native-library image in an
implementation-dependent manner.
Also the notes in the enhancement echo this sentiment
The source code for the loader is helpful
I'd fire up java under debug (gdb) and put a break point in at Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib. You're right, there aren't many great examples.
Related
We are trying to develop a Java application that loads a DLL (written in C++) and uses its functions.
When opening this DLL in "DLL Export Viewer" we can see the full signature of the functions exported, unlike any other DLL we load into the viewer:
Exported view of the DLL that doesn't work
We have tried to create some sample DLLs and load them to Java, and we were successful. The visibile difference was that when we loaded these DLLs we created into "DLL Export Viewer", we saw the functions without full signatures (only names):
DLL We created, works from Java
The code we use to load the DLL from Java is using JNA, and looks like this:
Declaring an interface that mathces the DLL functions:
public interface Ariel extends Library {
Ariel INSTANCE = (Ariel) Native.loadLibrary("ariel", Ariel.class);
void _ZN5ArielC1Ev();
int _ZN5Ariel8getArielEv();
}
Loading it and calling its functions:
public static void main(String[] args) {
Ariel ariel = Ariel.INSTANCE;
ariel._ZN5ArielC1Ev();
System.out.println("done");
}
Only when trying to load the DLL shown in the first image, we can't call any function and we always get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'resetScale': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:208)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:536)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:513)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:499)
at com.sun.jna.Library$Handler.invoke(Library.java:199)
at com.sun.proxy.$Proxy0.resetScale(Unknown Source)
at Bolet.main(Bolet.java:6)
Your DLL is exporting C++-mangled names. The DLL export is un-mangling them for you. If you examine the DLL with a different viewer, you should see the raw names instead.
If you want to export the names in a non-mangled manner, you need to use the extern "C" decorator on a given function declaration. This generally will only work for static methods (not class methods).
However, this is only part of your problem. If you want to directly map Java classes onto C++ classes, you'll need to use something like SWIG and compile some native glue code.
I have been through so many forum posts on similar issues, but I feel like I've seen it all. In short I have Native code through the wonders of JNI, accessed by Java. The code worked fine before I started using JAVA packages. I have followed all forum posts about ensuring the Javah cmd runs in the correct folder, and have successfully built my DLL. I have ensured that the package in which the wrapper is contained is present in the names of the C++ functions. Due to the size of the project I will simply show an example of this code. NOTE all the code (DLL's, JVM C++ Compiler) operates in 32-bit, and the target is a PC running windows 8.1.
All my Java Code is contained in the package:
package com.optin.executableContainer.client;
So in my Java wrapper class, I load the DLL(32-bit) expressly as follows
static
{
System.load("C:\\JNITests\\JNIBridge.dll");
}
I know this loads the DLL as without the DLL in that folder I get the "Cannot load library" Run-time error. The header code used, generated by the javah -jni command is
JNIEXPORT void JNICALL Java_com_optin_executableContainer_client_COMControl_setControlBackColor
(JNIEnv *, jobject, jlong);
The asscociated C++ code contained within a .cpp file is:
JNIEXPORT void JNICALL Java_com_optin_executableContainer_client_COMControl_setControlBackColor
(JNIEnv *env, jobject obj, jlong color)
{
printf("\nHello World\n");
}
There are no errors when I compile this with Visual Studio 2010. I have verified that this function exists within the targeted DLL, by using DLL export viewer which sees the function name as:
void __stdcall Java_com_optin_executableContainer_client_COMControl_setControlBackColor(struct JNIEnv_ *,class _jobject *,__int64)
However when I run this code, in the Eclipse IDE, I get the dreaded
Exception in thread "main" java.lang.UnsatisfiedLinkError:
com.optin.executableContainer.client.COMControl.setControlBackColor(J)V
at com.optin.executableContainer.client.COMControl.setControlBackColor(Native Method)
If I have missed something along the way, please point it out to me.
Regards
Jarren
UPDATED:
I went and compared the working dll (done before the packaging) and the new dll and spotted a few major differences. Here is the function name of the unpackaged working dll
_Java_COMControl_destroy#8
And here is the function name of the new packaged, unworking dll
void __stdcall Java_com_optin_executableContainer_client_COMControl_destroy(struct JNIEnv_ *,class _jobject *)
The Java code COMControl.java (that produces the COMControl header) declares this function as follows
private native void destroy();
I have tried comparing the differences between the header file that produced the working one and that producing the broken one, and other than the obvious packaging based changes (com_optin etc) there are no other differences. The only difference in the COMControl.java file is the inclusion of the package com.optin.executableContainer.client; at the top of the Java file.
What is going on here?
You are exporting the native routine as a name-mangled C++ function. The reason we can tell this is because the parameters to the function are listed in the export information of the library. Whenever you can tell the types of the parameters that are being passed in the name of a function it implies that the function is being exported as a decorated C++ method. If you looked at the raw export information of the library without demangling, it would look something like:
?Java_Package_ComControl_destroy##YGXPAUJNIEnv_##PAV_jobject###Z
When it looks like this, the java run-time cannot find it, it is supposed to look more like:
_Java_Package_ComControl_destroy#8
which is an undecorated C routine. The #8 is stdcall shorthand for 8 bytes are passed in the stack to the routine
The most common reason for this happening is that the .h file which declares the function and was generated by javah does not match the .cpp file that defines the content of the function - i.e. there is some subtle difference between the .h file and the .cpp file. You should copy-paste the declaration of the function in the .h file into the .cpp file, making sure that all the parameters line up and that all the types line up.
Additionally, for the .cpp file, you have to make sure that it #includes the .h file that was generated by javah, and doesn't just does #include <jni.h>. If you don't do this then the compiler will not know that the routine is to be exported as a C style routine. This is a common reason why the resulting compiled dll does not contain the unmangled version of the method.
If you want to manually enforce the routines being exported using the undecorated C calling convention, in the .cpp file, at the function definition, you can put in:
extern "C"
JNIEXPORT void JNICALL
Java_com_optin_executableContainer_client_COMControl_setControlBackColor
(JNIEnv *env, jobject obj, jlong color)
{
printf("\nHello World\n");
}
By using the extern "C" in that manner, the function will be defined for export as a C routine rather than a C++ routine; but this is undesirable as you should really be including the .h that came from javah.
I don't know if visual studio has an equivalent to the -Wmissing-declarations of gcc which notices inconsistencies like this, which are kind of important for .dlls.
I have a dll file and I am trying to call functions of it through a Java program through JNA
But the problem is It is not able to locate my dll file and throwing the following exception:
java.lang.UnsatisfiedLinkError: Unable to load library 'UsbDll': The specified module could not be found.
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:163)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:236)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:199)
at com.sun.jna.Native.register(Native.java:1018)
at com.MainClass.<clinit>(MainClass.java:15)
Exception in thread "main"
Below is my program:
package com;
import com.sun.jna.Native
public class MainClass {
static {
Native.register("UsbDll");
}
public native int method();
public static void main(String[] args) {
}
}
The name of my dll file is UsbDll.dll and my operating system is Windows.
============================ EDITED ================================
The location of my dll file is "c:\UsbDll.dll"
When I placed another dll file at the same location, JNA has located it so I think that the problem is with my "UsbDll.dll" file only.
When I tried to load both the dll files (UsbDll.dll and the another dll) with the following command
System.load("c:\\UsbDll.dll");
System.load("c:\\another.dll");
It loaded the "another.dll" successfully but for "UsbDll.dll", it throws the following exception:
java.lang.UnsatisfiedLinkError: C:\UsbDll.dll: Can't find dependent libraries
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1803)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1699)
at java.lang.Runtime.load0(Runtime.java:770)
at java.lang.System.load(System.java:1003)
at com.MainClass.<clinit>(MainClass.java:16)
Exception in thread "main"
Q1. It looks like it is not finding some dependent libraries. But as I am totally new to these dlls, Is there anything I am missing or I need to ask the vendor to provide me the dependent libraries.
OR
Is it depends on some standard libraries which I can download from internet? If it is, then how to find the libraries name on which it depends?
============================ EDITED #2 ================================
I ran the Dependency Walker on my UsbDll.dll file to find the missing dependencies and found the following missing dependencies.
WER.DLL (referred by library WINNM.DLL found in my c:\windows\system32)
IESHIMS.DLL (referred by library WINNM.DLL found in my c:\windows\system32)
WDAPI920.DLL (referred directly by my UsbDll.dll)
Q1. As WINNM.DLL was found in my system32 folder, it seems as the standard dll. And if this standard dll is referring to 2 missing dlls (WER.DLL & IESHIMS.DLL), then I suspect how other applications are working who are using this WINNM.DLL file?
Q2. I googled for WDAPI920.dll (that was referred my UsbDll.dll directly) and many search results appeared with the same dll name. So it also looks like some standard library. So how to fix these dependencies? From where to download them? After downloading, Can I place them in the same directory in which my main dll (UsbDll.dll) is or I need to do something extra to load my dll (UsbDll.dll) sucessfully?
From your edited code it is quite evident that the UsbDll.dll depends on some standard modules which are not there on your system (for example if it uses ATL and if you have don't have proper runtime then it is guaranteed to fail). To resolve this you will need proper runtime environment.
Also it is possible that the dll in concern depends on some vendor specific module. For you the best option is (and fastest option would be) to contact the vendor. Otherwise, try to install proper runtime from the microsoft site (but its more of hit-and-trial)
Update
Use the below links for finding more about DLL dependency:
How do I determine the dependencies of a .NET application?
http://msdn.microsoft.com/en-us/library/ms235265.aspx
Command line tool to find Dll dependencies
Update 2
See the below mentioned link for the missing dll details (but it is specific to the windows version)
Dependency Walker reports IESHIMS.DLL and WER.DLL missing?
http://social.msdn.microsoft.com/Forums/en/vsx/thread/6bb7dcaf-6385-4d24-b2c3-ce7e3547e68b
From few simple google queries, WDAPIXXX.dll appears to be some win driver related thing (although i am not too sure). Check this link, they have something to say about WDAPI http://www.jungo.com/st/support/tech_docs/td131.html.
The DLL must by in the Path specified by LD_LIBRARY_PATH (see your env), or, in the case of JNA, in the current directory.
How can I load a custom dll file in my web application? I've tried the following:
Copied all required dlls in system32 folder and tried to load one of them in Servlet constructor System.loadLibrary
Copied required dlls into tomcat_home/shared/lib and tomcat_home/common/lib
All these dlls are in WEB-INF/lib of the web-application
In order for System.loadLibrary() to work, the library (on Windows, a DLL) must be in a directory somewhere on your PATH or on a path listed in the java.library.path system property (so you can launch Java like java -Djava.library.path=/path/to/dir).
Additionally, for loadLibrary(), you specify the base name of the library, without the .dll at the end. So, for /path/to/something.dll, you would just use System.loadLibrary("something").
You also need to look at the exact UnsatisfiedLinkError that you are getting. If it says something like:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path
then it can't find the foo library (foo.dll) in your PATH or java.library.path. If it says something like:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V
then something is wrong with the library itself in the sense that Java is not able to map a native Java function in your application to its actual native counterpart.
To start with, I would put some logging around your System.loadLibrary() call to see if that executes properly. If it throws an exception or is not in a code path that is actually executed, then you will always get the latter type of UnsatisfiedLinkError explained above.
As a sidenote, most people put their loadLibrary() calls into a static initializer block in the class with the native methods, to ensure that it is always executed exactly once:
class Foo {
static {
System.loadLibrary('foo');
}
public Foo() {
}
}
Changing 'java.library.path' variable at runtime is not enough because it is read only once by JVM. You have to reset it like:
System.setProperty("java.library.path", path);
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);
Please, take a loot at: Changing Java Library Path at Runtime.
The original answer by Adam Batkin will lead you to a solution, but if you redeploy your webapp (without restarting your web container), you should run into the following error:
java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1715)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
at java.lang.Runtime.load0(Runtime.java:787)
at java.lang.System.load(System.java:1022)
This happens because the ClassLoader that originally loaded your DLL still references this DLL. However, your webapp is now running with a new ClassLoader, and because the same JVM is running and a JVM won't allow 2 references to the same DLL, you can't reload it. Thus, your webapp can't access the existing DLL and can't load a new one. So.... you're stuck.
Tomcat's ClassLoader documentation outlines why your reloaded webapp runs in a new isolated ClassLoader and how you can work around this limitation (at a very high level).
The solution is to extend Adam Batkin's solution a little:
package awesome;
public class Foo {
static {
System.loadLibrary('foo');
}
// required to work with JDK 6 and JDK 7
public static void main(String[] args) {
}
}
Then placing a jar containing JUST this compiled class into the TOMCAT_HOME/lib folder.
Now, within your webapp, you just have to force Tomcat to reference this class, which can be done as simply as this:
Class.forName("awesome.Foo");
Now your DLL should be loaded in the common classloader, and can be referenced from your webapp even after being redeployed.
Make sense?
A working reference copy can be found on google code, static-dll-bootstrapper .
You can use System.load() to provide an absolute path which is what you want, rather than a file in the standard library folder for the respective OS.
If you want native applications that already exist, use System.loadLibrary(String filename). If you want to provide your own you're probably better with load().
You should also be able to use loadLibrary with the java.library.path set correctly. See ClassLoader.java for implementation source showing both paths being checked (OpenJDK)
In the case where the problem is that System.loadLibrary cannot find the DLL in question, one common misconception (reinforced by Java's error message) is that the system property java.library.path is the answer. If you set the system property java.library.path to the directory where your DLL is located, then System.loadLibrary will indeed find your DLL. However, if your DLL in turn depends on other DLLs, as is often the case, then java.library.path cannot help, because the loading of the dependent DLLs is managed entirely by the operating system, which knows nothing of java.library.path. Thus, it is almost always better to bypass java.library.path and simply add your DLL's directory to LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS), or Path (Windows) prior to starting the JVM.
(Note: I am using the term "DLL" in the generic sense of DLL or shared library.)
If you need to load a file that's relative to some directory where you already are (like in the current directory), here's an easy solution:
File f;
if (System.getProperty("sun.arch.data.model").equals("32")) {
// 32-bit JVM
f = new File("mylibfile32.so");
} else {
// 64-bit JVM
f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());
For those who are looking for java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path
I was facing same exception; I tried everything and important things to make it work are:
Correct version of pdf lib.jar ( In my case it was wrong version jar kept in server runtime )
Make a folder and keep the pdflib jar in it and add the folder in your PATH variable
It worked with tomcat 6.
If you believe that you added a path of native lib to %PATH%, try testing with:
System.out.println(System.getProperty("java.library.path"))
It should show you actually if your dll is on %PATH%
Restart the IDE Idea, which appeared to work for me after I setup the env variable by adding it to the %PATH%
The issue for me was naming:
The library name should begin with "lib..." such as libnative.dll.
So you might think you need to load "libnative": System.loadLibrary("libnative")
But you actually need to load "native": System.loadLibrary("native")
Poor me ! spent a whole day behind this.Writing it down here if any body replicates this issue.
I was trying to load as Adam suggested but then got caught with AMD64 vs IA 32 exception.If in any case after working as per Adam's(no doubt the best pick) walkthrough,try to have a 64 bit version of latest jre.Make sure your JRE AND JDK are 64 bit and you have correctly added it to your classpath.
My working example goes here:unstatisfied link error
I'm using Mac OS X Yosemite and Netbeans 8.02, I got the same error and the simple solution I have found is like above, this is useful when you need to include native library in the project. So do the next for Netbeans:
1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: java -Djava.library.path="your_path"
5.- for example in my case: java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok
I hope it could be useful for someone.
The link where I found the solution is here:
java.library.path – What is it and how to use
It is simple just write java -XshowSettings:properties on your command line in windows and then paste all the files in the path shown by the java.library.path.
I had the same problem and the error was due to a rename of the dll.
It could happen that the library name is also written somewhere inside the dll.
When I put back its original name I was able to load using System.loadLibrary
First, you'll want to ensure the directory to your native library is on the java.library.path. See how to do that here. Then, you can call System.loadLibrary(nativeLibraryNameWithoutExtension) - making sure to not include the file extension in the name of your library.
I am trying to access the function available inside the .dll file. But it give exception like "Exception in thread "main" java.lang.UnsatisfiedLinkError: *.jniGetAudioInputLevel()D". DLL file is loaded but when I try to access the methods it give an error message.
According to my knowledge:-
This exception only occurs if the .dll is not in the class path or the dll is not present in the jar file.
.dll file is only created if all the code is running with out any error.
I have seen the methods in the dll using tools like for example: Anywhere PE Viewer, PE Explorer etc. They both are showing the methods available in the .dll file.
How this in accessibility to the function can be configured out by any other idea?
An UnsatisfiedLinkError is also thrown if the native counterpart to a method declared native can't be found. This can easily happen if the native code was not named with the full Java package name separated using '_'.
For example,
package com.mycompany.stuff;
public native void doSomething();
Requires that a native library (DLL, so, *SRVPGM, etc depending on your system) be found and loaded with System.loadLibrary(), which contains and exports a function named
com_mycompany_stuff_doSomething
If you are certain that the native library is being loaded, my guess is that the function is not correctly named, or is not exported.
I agree with Software Monkey, but I have one very significant addition related to the function name. The function name in native library should starts from '_Java_'. In your case it should be:
_Java_com_mycompany_stuff_doSomething
I found it by chance and spent two days to figure out why JVM cannot find the function in the DLL if it is there. In my case javah generates header file with function name without underscore sign before 'Java_'. Therefore, I had to update it manually in order to make it work.
I wonder why it was not mentioned about underscore prefix in "The Java Native Interface: Programmer's Guide and Specification", "Java Native Interface 6.0 Specification" provided with Java 6 Documentation (I worked with jdk 1.6.0_30, but the JDK version should not be the issue) and some other resources.
Normally we are getting this exception when JVM can't find the .dll file.