10

Long story short: I have an executable jar, that calls jni.dll which is dependent on lib.dll. And I'm getting the oh-so-dreaded UnsatisfiedLinkError.

This answer comes pretty close, yet it fails to solve the problem, from my experience. Even when the folder where the dll's reside is specified in java.library.path, it will not work. I have to change the Windows PATH environment variable as well. In fact, the default java.library.path on Windows seems to be PATH.

Is there any "pretty" way to fix this? I want to build an installer for Windows and I'm wondering how I would deal with this issue, so that the end-user will not have to do any manual work.

EDIT:

What I implemented is the following: the application ships with a folder called "native_libs" which has dynamic libraries for all supported architectures. The structure is the following:

/
+- native_libs/
   +- windows/
   |  +- x86/
   |  |  +- ...
   |  +- x64/
   |     +- ...
   |
   +- linux/
   |  +- x86/
   |  |  +- ...
   |  +- x64/
   |     +- ...
   |
   +- libs/
      +- ...

On runtime, while the application initializes, the correct JRE architecture and System OS are detected and the proper library files are copied to the libs/ folder. The java.library.path is being set on runtime as well using a common hack. Finally, the PATH environment variable for windows is set using a native launcher.

Any room for improvement? Maybe copying the dll's in the same directory as the jar file would negate the need for setting the java.library.path and PATH variables? I need to investigate loading the dll's with System.load() as well, which will negate the need to copy files.

JoshDM
  • 4,939
  • 7
  • 43
  • 72
alkar
  • 5,459
  • 7
  • 27
  • 43
  • Is there something else written for this error? Like "Could not find dependend libraries" or something similar? – Jakub Zaverka Sep 24 '12 at 16:44
  • Exactly that. I think I engineered a solution which is pretty dumb, but works and is at least transparent to the user. I will share once I'm sure that it works. – alkar Sep 24 '12 at 17:26
  • You can try to use the Dependency Walker to see what libraries are missing: http://www.dependencywalker.com/ – Jakub Zaverka Sep 24 '12 at 17:30
  • "Preloading" DLLs with `System.load()` does work on Windows, unless there's a circular dependency between your DLLs. Is there a circular dependency between `jni.dll` and `lib.dll`? – Samuel Audet Sep 25 '12 at 02:49
  • @SamuelAudet No there isn't a circular dependency, check my comment below. – alkar Sep 27 '12 at 13:01

4 Answers4

12

java.library.path specifies the directories where System.loadLibrary() looks for the dynamic library file. If you change the java.library.path system property in your code, it will not have any effect. There are hacks to make Java "forget" the initial value and re-evaluate the contents of the java.library.path system property.

However, the dependent library is not loaded by Java, it's loaded by Windows. Windows does not care about java.library.path, it only cares about the PATH environment variable. Your only option is to adjust PATH for your Java process. For example, if you start it from a batch file, change the PATH environment variable right before the java invocation.

Ingo Kegel
  • 46,523
  • 10
  • 71
  • 102
  • I understand the whole concept, what I'm asking for is for a way to do fix this "pretty", as I mentioned. And running a batch file is not "pretty", unfortunately. Do you have any other ideas? (by the way, when PATH has "." in it, should it be able to find the dependent dll? because apparently it does not). and yes, I've used such a hack to make sure that the proper JNI is loaded according to the OS / JRE arch – alkar Sep 24 '12 at 14:26
  • 2
    You cannot adjust environment variables in a running process. "." will work if the current directory contains the dependent library. I would recommend to use a native launcher generator, most of them allow you to adjust the native library path. – Ingo Kegel Sep 24 '12 at 14:31
  • As for the hack, the main point of my answer was to explain why this would not work for dependent libraries. – Ingo Kegel Sep 24 '12 at 14:32
  • 1
    upvoted for clarifying the way the whole thing works for anyone interested -- "native launcher generator" was a perfect term to google, thanks! – alkar Sep 24 '12 at 14:40
  • @IngoKegel I agree that Windows should use the %PATH% to load the `dependent library`. But in my scenario, I put the folder containing the `dependent DLL` into the %PATH% but the DLL still cannot be found. **But it works if I place the dependent DLL into the JDK's bin folder**. Thus some of my team members have blindly put all DLLs into the JDK's bin folder, which I think is a mess. Details here: http://stackoverflow.com/questions/29891114/must-i-place-all-dependent-dlls-into-the-jdks-bin-folder Appreciate if you can drop by. – smwikipedia Apr 27 '15 at 12:49
  • @IngoKegel And I accidentally found that, user variable %PATH% doesn't work. System variable %PATH% works. – smwikipedia Apr 27 '15 at 13:26
  • @IngoKegel I have found the root cause of my issue. – smwikipedia Apr 27 '15 at 14:34
  • Thank you so much. I couldn't figure this out, but adding the bin path to $Path$ in my debug configuration worked wonders. – Siebe Oct 17 '17 at 11:34
1

The simplest solution is to ensure that all .dlls are in '.' when you execute.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I need to check that. Are you sure that Windows will always look in "." for dll's? – alkar Sep 27 '12 at 12:52
  • Yes, it's a backwards compatibility issue: http://blogs.msdn.com/b/oldnewthing/archive/2010/11/10/10088566.aspx – Alex Cohn Mar 27 '13 at 06:36
0

If the problem is that the os can not find the dependency library, have you tried loading it via System.loadLibrary() before you load your main library?

Denis Tulskiy
  • 19,012
  • 6
  • 50
  • 68
  • @alkar: if nothing works, there's `System.load()` which takes a complete file path to the dll. – Denis Tulskiy Sep 24 '12 at 17:31
  • @alkar: also, post a complete stacktrace, please. – Denis Tulskiy Sep 24 '12 at 17:33
  • 2
    @EJP: nowhere in the javadoc of these methods does it say to load only jni libraries. See answers like this: http://stackoverflow.com/a/2906862/143585 where people actually managed to make it work by loading dependencies before the main library. – Denis Tulskiy Sep 25 '12 at 04:04
  • 1
    @alkar and EJP: Yes it works. I should know, I use that hack on Windows all the time. Something _else_ may be wrong with your code. – Samuel Audet Sep 26 '12 at 07:23
  • @SamuelAudet: yes, it should work according to google, it must be that i failed the two runtime dependencies of lib.dll – alkar Sep 27 '12 at 12:51
0

Put dlls your jni.dll depends on in your "current working directory", check this System.getProperty("user.dir") at runtime to get to know what is your "current working directory"

Jaime Hablutzel
  • 6,117
  • 5
  • 40
  • 57