jblas-project / jblas

Linear Algebra for Java
http://jblas.org
BSD 3-Clause "New" or "Revised" License
590 stars 149 forks source link

Windows 64 Library Missing Dependencies? #9

Closed buschness closed 13 years ago

buschness commented 13 years ago

When I try to run JBlas in 64-bit Windows, I get an unsatisfied link exception which actually looks to be a missing dependency:

-- org.jblas ERROR Couldn't load copied link file: java.lang.UnsatisfiedLinkError: C:\Users\chris\AppData\Local\Temp\jblas6440552492698981567jblas.dll: Can't find dependent libraries

If I run JBlas with 32-bit java on the same machine it runs with no problems. Unfortunately I don't have any idea how to dig around the dll to see what dependencies I'm missing.

mikiobraun commented 13 years ago

That is odd. I'll look into it and will get back to you.

mikiobraun commented 13 years ago

Actually, I do have an idea where this might come from... . Let me check... .

mikiobraun commented 13 years ago

Hello buschness,

ok, the problem is that you need to put the mings64 runtimes into your path. In particular, you need to have libgfortran-3.dll and

If you have cygwin, these are contained in the packages

mingw64-x86_64-gcc-core mingw64-x86_64-gfortran

Then, you need to put the directory

/usr/x86_64-w64-mingw32/sys-root/mingw/bin in your path. I'll try to link them directly into the jar file, but for now, you can add the above packages and libraries as a quick fix.
buschness commented 13 years ago

Thanks. It turns out that both libgfortran-3.dll and libgcc_s_sjlj-1.dll are needed.

As I was working on this, I was having a hard time getting java to find the correct dlls - not only the above dependencies, but also the jblas dlls so that a copy from the jar file wouldn't have to be made. I see in the LibraryLoader.java code you have the following paths you use to find the libraries:

    String[] paths = {
        "/",
        "/bin/",
        fatJarLibraryPath("static", flavor),
        fatJarLibraryPathNonUnified("static", flavor),
        fatJarLibraryPath("dynamic", flavor),
        fatJarLibraryPathNonUnified("dynamic", flavor),
    };

    InputStream is = findLibrary(paths, libname);

The issue here is that you are forcing the dlls to be in either the directory the program started in, or in a child "/bin" directory. If I put the dlls in my path, they aren't found. At the very least, you should add all of the paths from the system property 'java.library.path' as this is the standard place to search for native libraries. This defaults (on Windows) to the PATH variable, but can also be user-defined at runtime, allowing some level of customization. A simple fix would be to do the following:

    List<String> libPaths = Arrays.asList(
            System.getProperty("java.library.path").split(
                    System.getProperty("path.separator")));
    libPaths.add("/");
    libPaths.add("/bin/");
    libPaths.add(fatJarLibraryPath("static", flavor));
    libPaths.add(fatJarLibraryPathNonUnified("static", flavor));
    libPaths.add(fatJarLibraryPath("dynamic", flavor));
    libPaths.add(fatJarLibraryPathNonUnified("dynamic", flavor));

    String[] paths = libPaths.toArray(new String[libPaths.size()]);

    InputStream is = findLibrary(paths, libname);

The other issue is that even if the library is found outside of the jar file, you still copy a temporary version of it. The copy takes only a fraction of a second, so performance-wise it doesn't matter, but it is superfluous. It would be nice if you only copied the library if it had to be pulled from the jar file, and otherwise would load the library already on disk.

mikiobraun commented 13 years ago

Hello buschness... .

actually, it should behave exactly as you say: First load the library from the path, and only then extract it from the JAR file.

If you look at org.jblas.NativeBlas in the static block at the beginning, I first try to just load the library "jblas" with System.loadLibrary("jblas"), and only if this fails I go through the whole process of trying to extract the shared library from a file (BTW, the paths are meant with respect to the JAR file, not in the actual file system, although I guess JAVA will also look there).

So I wonder why the initial System.loadLibrary("jblas") fails in your case. That should honor your java.library.path settings... .

-M

buschness commented 13 years ago

You are right, it does load the library from the java.library.path - the reason I was confused was I didn't leave the debugging on when I got it running. Basically, when I had jblas.dll in my path, but not the gcc dependencies, the unsatisfied link error would be caught by your static block in NativeBlas.java, and then that would kick off the attempt to copy the library from the jar file. Even though it did find the jblas dll, the missing dependencies made it look like it didn't.

So all is well. Sorry about the confusion.

mikiobraun commented 13 years ago

No problem... . You are right, that might be a bit confusing... I'll see whether one can probably see from the exception what kind of error it was.