10

Is there a platform-independent Java statement to load a native library from a different directory than the Java source code is in? I would like to use something like this:

public class HelloWorld {
    static {
        System.loadLibrary("../some_project/HelloWorld");
    }

    public static native void print();
}

The problem is that System.loadLibrary() doesn't support directory separators in the pathname argument. Also, System.load() unfortunately requires an absolute pathname, which not only means I can't specify a relative directory as above (which I would like to do), but it also requires the argument to include, for example, the preceding "lib" and ".so" extension on the JNI library name on a Linux system.

Is there a standard way of dealing with this? If possible, I would like to avoid writing a bunch of platform-dependent Java code just to construct the correct JNI library name.

jvm_update
  • 265
  • 2
  • 9
  • Wouldn't it be more stable if the path was relative to e.g. your .jar file rather than the "current directory". That is bound to give you problems in the long run if the current directory is something different (e.g. because of a Desktop shortcut) –  May 21 '12 at 23:10
  • That's a good point, thanks for pointing this out. I don't know how to use a path relative to a .jar file, but to avoid asking a second question in a comment, I'll just link to a few other stackoverflow questions which seem helpful: http://stackoverflow.com/questions/2837263/how-do-i-get-the-directory-that-the-currently-executing-jar-file-is-in http://stackoverflow.com/questions/5053150/how-to-know-jar-file-directory http://stackoverflow.com/questions/779650/where-on-the-file-system-was-my-java-class-loaded-from – jvm_update May 23 '12 at 20:30
  • The first questin (the one using `getProtectionDomain()`) is the only correct answer to that problem. –  May 23 '12 at 21:50

2 Answers2

22

I believe you're looking for System.mapLibraryName, which is the method typically used by ClassLoader.findLibrary implementations. For example:

File lib = new File("../some_project/" + System.mapLibraryName("HelloWorld"));
System.load(lib.getAbsolutePath());

This will use libHelloWorld.so on Linux and HelloWorld.dll on Windows. Be aware that some operating systems support multiple extensions, and mapLibraryName can only support one, by design. The ones I'm aware of are MacOS (.dylib primarily and .jnilib for legacy) and AIX (.a and .so).

Brett Kail
  • 33,593
  • 2
  • 85
  • 90
  • 2
    Thanks! That is what I was looking for. I just tried it and it works great. Just for reference of anybody else who reads this, System.load() requires an absolute path name, so the directory has to be made absolute and a trailing slash added, e.g., with the code: new java.io.File("../some_project/").getCanonicalPath() + "/" – jvm_update May 21 '12 at 22:46
  • 1
    I've updated the answer to include the `getAbsolutePath`, thanks. – Brett Kail May 21 '12 at 22:49
  • 1
    +1 mapLibraryName is the piece in the jigsaw that I knew nothing about – David Heffernan May 22 '12 at 06:10
0

Well, as you have clearly explained, you can't use loadLibrary. And so that leaves load. But that requires an absolute path. So, expand your relative path into an absolute path using your preferred file path utility functions, and pass that on to load. This may seem inconvenient but it's much more robust than relying on the vagaries of library search paths.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Expand it to an absolute path how? More importantly, how can the loading be done in a portable way? The library would have three different filenames on three different platforms: HelloWorld.dll (Windows), libHelloWorld.so (Linux), and libHelloWorld.jnilib (Mac OS X). What line(s) of Java code would automatically select the appropriate name on the appropriate platform without me hard coding a switch statement into the Java code? – jvm_update May 21 '12 at 21:13
  • Well, a relative path is relative to something. So put that something in front of the relative part and you have your absolute path. As for the extension, I don't know if there is anything built in, but it should be easy enough to detect platform and switch. – David Heffernan May 21 '12 at 21:19
  • My goal is to have the ability to port the application to a new platform without needing to recompile the Java part of the application. That is, the compiled Java code should be portable. Having an explicit check to see what operating system the code is running on is unfortunately not platform independent. – jvm_update May 21 '12 at 21:28
  • Then find a way to use loadLibrary in that case – David Heffernan May 21 '12 at 21:31
  • 1
    That is exactly what the original question was asking how to do. – jvm_update May 21 '12 at 21:46
  • Go ahead and use loadLibrary then. Just live with the limitation on file location for the library. – David Heffernan May 21 '12 at 21:51