18

I'm running a library via JNI (I didn't write it), and internally it calls another DLL. I get an error saying "Can't find dependent libraries" unless I put the path of the other DLL on the system PATH variable (I'm on Windows XP). I'd like to be able to handle this on the java command line, and I've already tried adding it to -Djava.library.path and to the classpath, neither which worked (I expected -Djava.library.path to work but not classpath, but neither worked). Is there a way to do this?

thanks,

Jeff

Jeff Storey
  • 56,312
  • 72
  • 233
  • 406

6 Answers6

19
  • If you have a DLL name 'MyNativeDLL.dll' then you should use 'MyNativeDLL' in your LoadLibrary call.
  • Use Dependency Walker to check if there are any files required by MyNativeDLL.dll
  • If there are, include them in the same folder as MyNativeDLL.dll - one you get it working try putting the additional required files in System32 folder.
Vivek
  • 16,360
  • 5
  • 30
  • 37
  • 1
    that would work, but I'd like to have the dependent DLLs be in any folder they want and then just reference that folder. is that possible? – Jeff Storey Jul 06 '09 at 14:09
  • 1
    we had similar situation where we had to load OurJNI.dll and OurNative.dll using the LoadLibrary call. Again, the order in which they are loaded matters. We couldn't find any other way to do this. – Vivek Jul 06 '09 at 14:18
  • 3
    Right - welcome to DLL hell. In our case, I'm only loading A.dll which internally references B.dll so B should always be loaded after A. I was just trying to avoid modifying the PATH variable. – Jeff Storey Jul 06 '09 at 14:21
  • Dependency Walker help me identify one missing dll on my system. Thanks +1 – h3xStream Aug 11 '12 at 03:43
  • Same here. I have to also do first `System.loadLibrary()` the other DLL that is needed by the main `JNI` DLL. And now it works... – daparic Jun 06 '20 at 22:10
  • 1
    There is also the https://github.com/lucasg/Dependencies tool that is actively maintained. It claims to be a rewrite of Dependency Walker. It performed much better on my Windows 10 system and gave me my answer more quickly. – NaderNader Feb 25 '21 at 12:57
9

I was able to get this to work without putting any DLLs on the PATH by using System.load() on all DLLs in reverse dependency order. Just to be clear, I was calling System.load() on all dependent DLLs, not just JNI DLLs. You don't have to call System.load() on DLLs that come with Windows (they're on the PATH).

I was doing this in a web app where a jar included DLLs that were getting unpacked. Your situation seems simpler, so I believe it should work. I generally followed the solution here: How to make a JAR file that includes DLL files?

Community
  • 1
  • 1
Liron Yahdav
  • 10,152
  • 8
  • 68
  • 104
  • true. I first loaded the other DLL that is needed by the main `JNI` DLL and now it works. The two DLLs are custom DLL that I made where the `JNI` is just some sort of adapter DLL and the other DLL is the meat. – daparic Jun 06 '20 at 22:13
2

This helped me a lot. Also managed loading a JNI dll built using cygwin:

first:

/* conditioned if OS is windows because also need it to work in Linux env. */ 
System.loadLibrary("cygwin1"); 

then:

System.loadLibrary("mylib"); 

On windows, This requires either setting the java.library.path to match both libraries locations.

If runnning from Eclipse, this setting may be replaced by "Native Libraries Location" in java build path (in JRE libraries settings).

However, still finding this a bit tricky.

Stewartside
  • 20,378
  • 12
  • 60
  • 81
1

For me, making a static build worked, which compiles with:

g++ -static

It adds the dependent libraries in the build itself.

Caesar
  • 1,092
  • 12
  • 19
0

I've successfully injected a folder into the PATH variable using JNA. This can be used as a workaround if you want to deploy your dependent DLLs alongside your application without tainting the global environment or messing with explicit DLL load order.

However it's not clear to me how the classloader lifecycle affects this. I've only tried this technique under the NetBeans module system, but if you look through the ClassLoader class code for loadLibrary, you'll see that it caches some path variables. It may or may not be necessary to create a new classloader to load the library on.

The downside is you need to use JNA or JNI. Also, it seems like a pretty gross hack. See here for an example of how to set an environment variable using JNA.

gibbss
  • 2,013
  • 1
  • 15
  • 22
0

I had a similar problem. My requirement was to load the following library in a windows environment:

System.loadLibrary("ibex-java");

In my case, I had configured the -Djava.library.path=C:\projetos\platform\windows\ibex to a folder where all required dlls were stored.

C:\projetos\platform\windows\ibex>dir
21/08/2020  14:49    <DIR>          .
21/08/2020  14:49    <DIR>          ..
21/08/2020  07:47    <DIR>          ibex
21/08/2020  14:49           128.108 ibex-java.dll
21/08/2020  14:49             8.554 ibex-java.dll.a
21/08/2020  14:49         6.582.641 ibex.dll
21/08/2020  14:49         5.577.792 ibex.dll.a
21/08/2020  07:47           938.157 libgcc_s_dw2-1.dll
21/08/2020  14:49         6.349.752 libibex.a
21/08/2020  07:47         1.508.122 libstdc++-6.dll

However when I tried to load this library the following error was thrown:

Caused by: java.lang.UnsatisfiedLinkError: C:\platform\windows\ibex\ibex-java.dll: Can't find dependent libraries

As we can see, all dependent dlls are in the same folder of the library path. However, the single line System.loadLibrary("ibex-java"); couldn't automatically load them. One option to solve this problem was to put the library path in the PATH environment variable of windows, but I didn't like this idea. In my case I find a better solution, find the DLLs dependencies and load these libraries by-hand. For example:

System.loadLibrary("libgcc_s_dw2-1");
System.loadLibrary("libstdc++-6");
System.loadLibrary("ibex");
System.loadLibrary("ibex-java");
João Pedro Schmitt
  • 1,046
  • 1
  • 11
  • 25