I have written some JNI hooks into a C++ library and created some DLL files for my java server project. Lets say the DLL and jar files are in the same folder under "C:/server"
I am accessing these DLL files using:
System.loadLibrary("someDLLFile");
in the class that needs the C++ code.
The problem I am running into is when I run this server on my own machine, everything works fine regardless of where I place the "server" folder. But when I give it to a colleague to test, they continually get:
java.lang.UnsatisfiedLinkError no someDLLFile in java.library.path
I want to have the DLL files live in the same folder as the jar files and would prefer not having someone configure their PATH variable.
Why does System.loadLibrary() work on my own machine regardless of the folder's location, but not on another computer?
It works because the DLL (or a DLL it depends on, i.e. msvcr90.dll or something) are in the PATH on your machine, but not on the other one.
Either set PATH env-var or the java.library.path property to contain the dir with your file, or store your dll where java finds it by default (Many options here, depending on deployment strategy and platform).
One option is to specify the directory in the command line when you start the VM:
java -classpath C:\server -Djava.library.path=C:\server somePackage.Main
Another option is to use System.load instead of System.loadLibrary.
URL url = Test.class.getResource("someDLLFile.dll");
String f = new File(url.getFile()).getAbsolutePath();
System.load(f);
The downside is that your program is now dealing with platform-dependent directory names, file extensions etc.
I'm not sure if this is helpful or not, but I have included the following in some projects:
http://forums.sun.com/thread.jspa?threadID=707176
To load native libraries.
And then I just load the bin directory
String binPath = new File(".").getAbsolutePath()
+ System.getProperty("file.separator") + "bin";
addDir( binPath );
It works pretty well.
But Again, I'm not sure if this is the case or not.
Try downloading depends.exe to see if the dll depends on other dlls on the system or not. If it does, then check the other machine, whether such dlls are present or not in Path.
Related
The Java application has the JNI module to use.
Where should a user (or an installation script of this application) put the JNI module on Linux (Ubuntu) or on MacOS X so that this JNI module could be loaded without specifying the path to the module in code?
This is a link to a detailed explanation of shared objects and how they are searched for by the OS.
I wish Java people would stop using LD_LIBRARY_PATH and start using the existing directory structures and the ld.so.conf mechanism. Even the OpenJDK libraries are dumped in a place that's not on a standard path and they don't add an ld.so.conf file either ( just how hard is that ? ).
This approach avoids the need to set up your own LD_LIBRARY_PATH and launch via a shell script.
If a required shared object is to be installed, first test for somewhere like /usr/local/lib as an installation choice system wide, and if it exists and an existing file does not already use your file's name, then put your library there. A more systematic approach would be to check all the ld.so.conf files and see if any of the directories match something you know can be used. A shell script can do that at install time.
Put the compiled libraries (.so files on Linux or .dylib on MacOS) into a directory of your choice and include this directory in the library search path LD_LIBRARY_PATH used to start your JVM.
This is the directory structure I want to create when I finally deploy my software. It is a Java chat client with a webcam feature and for the webcam I am using LTI-CIVIL.
I was told that I can not use DLLs right from the JAR and I will have to extract them somewhere. All cool. However, what I cannot get my head around is how can I make it work ?
LTI comes with a large number of files in the zip that they provide on their site. If you are using Eclipse, you need to set the path to appropriate folder for the native library. However, this limits me to Eclipse and prevents me from distributing the JAR to my friends. Apparently, I will now have to point to that folder, and maybe load the files, programatiaclly
I am a beginner so if someone can download LTI-CIVIL, have a look at the directory structure and let me know how to achieve what I am trying to do then that would be highly appreciated.
AFAIK, for my 32 bit Windows, I need to point to native/win32-x86 folder.
What I am trying to do is to load the appropriate files in memory so that I can provide webcam facility. I want to avoid installers and simply give a zip file with a directory structure mentioned above so that people can extract, run the jar file from the folder and start chatting.
Clarification: I am trying to send a library with jar file and not in jar. I know extracting and using dlls from jar is tough
I'm assuming that it is not your own code which loads the native libraries (System.load), and they are loaded by a third-party jar (lti-civil).
In this case you have to set the enviroment variable LD_LIBRARY_PATH appropiately before lti-civil attempts to load the native libraries.
Either:
With a launcher script (e.g .bat), set the variable before running java, or set the system property, something like:
java -jar your.jar -Djava.library.path=/path/to/native/folder
At runtime. In the entry point of your program.
This is a bit "hackish", but it works.
Check this link for example:
http://nicklothian.com/blog/2008/11/19/modify-javalibrarypath-at-runtime/
Since you do not know the exact path beforehand, in both cases you will have to also find the correct path where the native libraries are located.
If the path to the libraries is relative to the path of the jar/launcher, then find the current path of the executable:
in a .bat launcher:
Get Directory Path of an executing Batch file
in java:
How to get the path of a running JAR file?
And then that, you can assume the libraries are located in path relative to this (../native), just calculate the path (and maybe expand it to an absolute path).
After you have calculated the absolute path, set the enviroment/system property as described in the first part of the answer.
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.
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");
I am using JNI to wrap a few native functions in a closed-source PDF library. It has an dependent fonts directory which must be in a subfolder of the calling application's directory. In my experience, it is standard to seek based on the current working directory. Thus, the problem.
When loading the JNI code into a Java application, the current working directory is correct. However, the calling application's directory is java.exe's bin directory. I have verified that putting the dependent fonts folder in C:\Program Files (x86)\Java\jre6\bin folder works as expected.
The library seems to be using a C++ GetCommandLine() call, or something similar to determine where the fonts directory should be. Obviously, this is an unacceptable solution.
I'd like to avoid calling an external EXE. But the only workarounds that I've come up with are:
Compile an EXE, place in Java project directory, and use Java's Runtime.exec() to execute. (this does work)
Make JNI code launch a separate process which does the same as above (gains nothing but more complexity)
Any ideas on how I can circumvent this problem? When Java applications are compiled as a runnable JAR, is the resultant command line still the JRE's C:\Program Files\...java.exe?
A Java executable maker can create an executable *.exe from your Java application without any native coding or compiling. You can put that executable, the jar files, the fonts and other application dependencies into a single install directory.
Exe4j is one of the executable makers that will support this, for Windows. It does not require any assumptions about the current working directory. This is important in the frequent case where you have no control over what the working directory is when the application is launched.