UnsatisfiedLinkError When Loading a Library from Java in MATLAB - java

I've been integrating simple java modules into the MATLAB environment on Windows with some success. Recently I encountered a problem with a third-party library which attempts to load a dll.
The java ClassLoader throws the UnsatisfiedLinkError when the load is attempted:
java.lang.UnsatisfiedLinkError: no <libname> in java.library.path
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
The exception is reporting that my 'libname' is not in the java.library.path property. I have verified that the property does indeed have the correct path in it, and that the libname.dll file exists on that path.
I verified java.library.path in two ways. First, I simply checked that value returned on the MATLAB command line:
>> java.lang.System.getProperty('java.library.path')
Then, I modified the java method in question to print that value just before the call into the failing third-party function:
System.out.println(System.getProperty('java.library.path'));
Both confirmed that my path value was set as expected.
I've also tried manually loading the library from the command line, and it fails with the same results.
Is this something that is not possible in MATLAB, or am I missing something here? Unfortunately I'm not administrator on this machine so I can't try the old trick of moving the dll into a directory with dlls that do work.
I welcome any suggestions for things to try if there is no absolute answer.
Platform:
Windows XP
MATLAB R2009a
Java 1.6

Are you familiar with Process Monitor? (If not you will easily get how it works).
Download it. Run it. Just enable "Show File System Activity" (little icons on right under menu-bar), disable the others.
Then fire up whatever causes the library to try to load the dll. After the UnsatisfiedLinkError occured, stop the event capturing in Process Monitor.
Now do a CTRL+F and search for the name of the dll it should load. Check the (probably multiple) entry which say "Not Found" or "Name not found" in the result column and with the dll-name in the path column.
Now check where it really looks for the dll. Maybe it appends some additional path or similar and thus can't find it.

Just found this in the MATLAB docs:
Specifying the Search Path for Sun Java Native Method DLLs
The mechanism that MATLAB uses to locate native method libraries that are required by Java has changed. MATLAB no longer uses system environment variables to define the paths to these libraries.
Compatibility Considerations
If you presently rely on the PATH (for Windows) or LD_LIBRARY_PATH (for UNIX) environment variables for this purpose, you will need to use the file librarypath.txt, as described below, in its place.
Specifying the Java Library Path
Java classes can dynamically load native methods using the Java method java.lang.System.loadLibrary("LibFile"). In order for the JVM software to locate the specified library file, the directory containing it must be on the Java Library Path. This path is established when MATLAB launches the JVM software at startup, and is based on the contents of the file
$matlab/toolbox/local/librarypath.txt
(where $matlab is the MATLAB root directory represented by the MATLAB keyword matlabroot).
You can augment the search path for native method libraries by editing the librarypath.txt file. Follow these guidelines when editing this file:
Specify each new directory on a line by itself.
Specify only the directory names, not the names of the DLL files. The LoadLibrary call does this for you.
To simplify the specification of directories in cross-platform environments, you can use any of these macros: $matlabroot, $arch, and $jre_home.

Put the DLL that you try to load using java.lang.System.loadLibrary into the following directory:
$matlabroot\sys\java\jre\win??\jre\bin\

Does your library depend on other dlls? It could be that the dll java is loading as a result of its loadLibrary() call requires other dlls. On Windows, I believe it will look on %PATH% to try to find these dlls.
This isn't strictly a java thing; it's more to do with the native library you are loading.
Java is told where to find the dll via java.library.path (or whatever other mechanism Matlab uses), and the libname.dll will use %PATH% to find any dlls it depends on.
As you say that the missing dll is in your java.library.path, perhaps you could try appending the java.library.path value to %PATH% and trying again?

Related

Using JNI without having to add jvm.dll path inside Environment Variables (User or System) [duplicate]

I am using MinGW to create a shared library that is dynamically linked and loaded using the LoadLibrary function. My shared library is dependent on a dll that can be found in two different places on the path. These two are different (two different versions) and at the time of loading the library, it picks the wrong dll. How can I explicitly specify which dll to pick?
To be more specific these are the commands I am using:
Compilation
g++ -m64 -O3 -c my_file.cpp -o myfile.o
Creating shared library
g++ -m64 -shared myfile.o -o myfile.dll
I have tried many things including -L option but have not yet been able to figure out how to do this. I also have searched online for a couple of hours but it turn out to be of no use.
Any help is much appreciated.
Thanks in advance
It turns out that the dll I don't want to load is indeed at "The directory where the executable module for the current process is located." The other dll, with the same name is on the path but not where windows looks first. From what this document says, LoadLibrary will always pick the dll from the directory where the executable module for the current process is located, if the dll exists there, no matter what. Is there a way around this? Moving the dlls is really not an option as this is a third party program that we are building on
The chronological order of, how windows looks for DLLs is explained here step by step
https://msdn.microsoft.com/en-us/library/7d83bc18.aspx
After all steps in above link, when it comes to PATH environment variable, windows looks through each directory listed in PATH variable, from left to right.
First try if you can place the correct DLL in any of the locations as listed in the above link. Because path environment variable is the last thing that gets looked into.
If the above step is not possible, then ensure the correct DLL path is on the left of the wrong DLL path in PATH environment variable.
The following article gives some guidance for effecting alternate DLL search strategies using the SetDllDirectory and LoadLibraryEx API calls, assuming those are options (you mentioned LoadLibrary is currently used).
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx
It turns out that there is another windows function called LoadLibraryEx that allows to explicitly specify a path where the libraries will get loaded. You can learn more about it here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
Specifically, as the docment mentions:
If this value is used and lpFileName specifies an absolute path, the
system uses the alternate file search strategy discussed in the
Remarks section to find associated executable modules that the
specified module causes to be loaded.
and
If lpFileName specifies an absolute path and dwFlags is set to
LOAD_WITH_ALTERED_SEARCH_PATH, LoadLibraryEx uses the altered search
path.

JNA library path seems to be ignored

I'm trying to specify the library load path for JNA on linux for a C++ library.
From the java doc I used -Djna.library.path when calling my program but JNA fails to load the library.
This is how I call the program:
java -jar -Djna.library.path=/home/lib program.jar
When I use -Djna.debug_load=true I can see the library path and JNA trying to find the library, the path is correct and the library name is also correct, but it doesn't load. JNA continues to search the resource path for the library and then fails to find it.
When I put the library in the current directory (same level as program.jar) JNA is happy and the library is loaded without issue.
When I use:
java -cp program.jar:/home/lib package.program
JNA also loads the correct library.
Does anyone here know why -Djna.library.path does not work? Is it because I'm using a jar application file with a manifest?
Anyone with a similar problem?
Please note that once you leave JVM, jna.library.path or java.library.path is no longer taken into account.
Make sure to set LD_LIBRARY_PATH such way it points to locations where libshared.so is located.
Update:
Take a look here to check how using code from shared lib works:
https://github.com/mkowsiak/jnicookbook/blob/master/recipes/recipeNo023

java.lang.UnsatisfiedLinkError - Native method issue

I am experiencing a problem in Java (Eclipse) regarding the usage of dlls. Until now, I am experiencing the following problem:
Uncaught Exception for agent SomeAgent
java.lang.UnsatisfiedLinkError: SomePackage.SomeClass.SomeNativeMethod(II)Z
[...]
at jade.core.behaviours.Behaviour.actionWrapper(Behaviour.java:344)
at jade.core.Agent$ActiveLifeCycle.execute(Agent.java:1532)
at jade.core.Agent.run(Agent.java:1471)
at java.lang.Thread.run(Thread.java:745)
I don't know if this will help to figure out the problem, but I am also using JADE in this project...
EDIT (28/04/2014):
The dll which I am trying to use is a custom one (was created by an ex-employee from the company where I work).
The curious thing about this problem is that I have 2 java projects which perform similar tasks. One of this projects runs perfectly, while the other one is experiencing the UnsatisfiedLinkError.
About the paths: I've created a specific folder for the dlls which is contained in the workspace folder, but not inside the project folder (in other words, the same folder where bin, src, bibs, settings, etc. are). This folder's configuration is equal for the both projects I have. Also, I've already tested the System.out.println(System.getProperty("java.library.path") method and the right path is returned on both cases.
EDIT (29/04/2014):
Just added some additional information regarding the error messages. I am starting to think that the problem may be related to the JADE usage...
Here is a PD procedure that might help you identify the problem.
Add the following to your program to identify the differences in the arch and load paths between the two runtime environments. Investigate any differences in path/arch.
System.out.println(System.getProperty("java.library.path"));
System.out.println(System.getProperty("sun.arch.data.model"));
You can use the dumpbin.exe utility to identify the dependencies needed by the DLL that is being loaded.
Make sure the dependencies exist.
Example usage:
C:> dumpbin /imports your.dll
Dump of file your.dll
File Type: DLL
Section contains the following imports:
**KERNEL32.dll**
You can use the where.exe command to find the location of the dependencies.
Example usage:
C:>where KERNEL32.dll
C:\Windows\System32\kernel32.dll
If you see:
C:>where KERNEL32.dll
INFO: Could not find files for the given pattern(s)
Investigate why the dependent DLL is not on the path.
You can use the dumpbin.exe command to check 64bit vs 32bit.
Example:
C:>dumpbin /headers yourd.dll
Dump of file yourd.dll
PE signature found
File Type: DLL
FILE HEADER VALUES
14C machine (x86) <-- 32bit DLL
C:>dumpbin /headers yourd.dll
Dump of file yourd.dll
PE signature found
File Type: DLL
FILE HEADER VALUES
8664 machine (x64) <-- 64bit DLL
Investigate any 32bit vs 64bit mismatches between main/dependent. If your JVM is 32bit, you need to use 32bit DLLs. If your JVM is 64bit, you need to use 64bit DLLs. ( It is okay to run a 32bit JVM on a 64bit OS but the JNI DLLs must be 32bit ( DLLs match the JVM not the OS ).
Contrary to several answers here, this is not a library loading problem. See the stack trace. It's a problem locating the method named in the exception. This is caused by a mismatch between the actual and expected names. Popular causes:
not using javah to generate the .h file
method signature in .h and .c/.cpp file do not agree
not including the .h file in the .c or .cpp file
changing the package or name of the Java class after running javah
changing the method name or signature after running javah
If you do either of the last two you must re-run javah and adjust the .c/.cpp file to agree with the new signature in the new .h file.
This might be due to version mismatch or bit mismatch of your library. You may be working on 64 bit OS, use 64 bit compatible versions of your JAR files. Also check for version mismatch between JARS.
When you use some native library your system will check it in both environment variable and java.library.path. system property if it does not found there then it will throw java.lang.UnsatisfiedLinkError. Windows pick dll form system32 because system32 folder already exists in the path so there is very less change of error form this side. Native libraries make java code platform dependent. Check your java path for the required dll. Check your java.library.path and try to load your library(without dll extension) by using System.loadLibrary("library name"). Hope this help. :)

Why can my Java project call my DLLs successfully in Eclipse when I place them in JAVA_HOME\jre6\bin but failed in using java.library.path?

After doing some research, some people say I can add the following VM Argument in my project Run Configuration. In run time, JVM will search these directories to find DDLs.
-Djava.library.path="${workspace_loc}/GunCalibration/myLib/DLLs;${env_var:PATH}"
GunCalibration is my Java project folder in my workspace.
DLLs folder contains all my DLLs which are defined with my JNI specification.
As a result, I get this error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: D:\Software
x64\eclipse3.7\Kai\workspace_RealW\GunCalibration\myLib\DLLs\sixense.dll:
Can't find dependent libraries
However, if I copy some specific dll files to JAVA_HOME\jre6\bin, my code works correctly. (I do add this path into my system environment PATH.)
Could anyone explain why the first approach by using java.library.path doesn't work? How can I know which ddl is required to place in JAVA_HOME\jre6\bin?
Thank you a lot~
JAVA_HOME\jre6\bin is effectively in the system PATH (since it's the same directory as the java.exe program which is being run), which makes any DLLs there loadable by the system. java.library.path is mostly derived from the value of PATH, but it only affects where the VM looks for native libraries, not the system itself.
The VM can load any file explicitly based on the paths in java.library.path, but it cannot affect how the system looks up any dependent DLLs (other than telling the system to include the path to the initial DLL in its search -- see MSDN for LoadLibrary[Ex])
One alternative to copying the DLLs is to add the path to the DLLs to the PATH environment variable.

Importing DLL into Eclipse Java project

To import DLL into Eclipse Java project, I checked the "java.library.path"
String path = System.getProperty("java.library.path");
System.out.println(path);
One of the path values was equal to C:/Windows/System32. Therefore I saved myAPI.dll in C:/Windows/System32. Then I called System.loadLibrary:
System.loadLibrary("myAPI.dll");
And got the error message:
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: Expecting an absolute path of the library: myAPI.dll
at java.lang.Runtime.load0(Unknown Source)
at java.lang.System.load(Unknown Source)
BTW, I tried to put my DLL file in different other directories that was mentioned in path. But each time I got the same error message. How to solve this problem?
Don't put ".dll" at the end of your library. That is a Windows-specific extension, and your call will work on other systems with other extensions, so putting the extension on is incorrect. Just load "myAPI" and, if that's the right names and other things are as advertised, it will work.
One option is to try keeping that dll in your /jre/bin used in eclipse system library and was able to configure dll files at runtime , by placing dll in /jre/bin
It is the simplest way i could find out. This work for me.Hopefully will help you.:)
If the dll is in your project folder (e.g. part of your project), i.e.:
./prod/bin/myAPI.dll
and you want to execute the program/unit test within eclipse you can configure the runtime environment which runs your program. Go to "Preferences/Java/Installed JREs", choose the desired JRE or JDK (note: for loading a 32bit dll you must use a 32bit JRE, although your host system is a 64bit system), click on "Edit". In the box "Default VM arguments" you enter
-Djava.library.path="./prod/bin;${env_var:PATH}"
This adds your dll folder "prod/bin" in front of the system path (don't bother, it's not permanently, only for the environment of the chosen JRE).
By running following code you can verify that the system path was updated and the dll can be loaded:
String path = System.getProperty("java.library.path");
System.out.println(path);
System.loadLibrary("myAPI");

Categories

Resources