I have the following distribution
.__bin
| |__start.sh
|
|__lib
|__Main.jar
|__Utility.jar
|__lib.so
Main.jar contains main method, in which I would like to access native functions provided by the lib.so bundled in the distribution. start.sh simply sets the classpath and bootstraps java.
What is the best approach to load the lib.so library inside the application? I am aware of two methods:
System.load(absolute path)
System.loadLibrary(name)
Former requires the absolute path of the library in the file system, latter requires setting the application specific java.library.path JVM argument. Which is better solution in this case? Would setting the library path in the start.sh script possibly break something? How could I get the absolute file system path of the library for the former solution?
Assuming I am not missing anything, isn't setting System.load the best approach? Your lib.so is not going to change since you have it in your structure. If you would want to give control to the end user to load the native/shared library from elsewhere have an optional parameter in start.sh. Else use the System.load().Just make sure to check the type of OS, since you will be having the different formats for file paths.
The load() method requires the complete path name of the library as an argument. For example, on a Solaris system you might write:
System.load("/home/me/libs/libmylib.so");
to load the libmylib.so library in the /home/me/libs directory.
Using the load() method is system-dependent because it uses a pathname to load the library and pathnames are usually system-dependent. Thus, loadLibrary() is sometimes a better choice. However, dynamically loadable libraries are system-dependent in nature so the use of load() may not compromise system-independence any more than the act of loading the library itself.
The loadLibrary() method requires just the name of a to load:
System.loadLibrary("mylib");
The loadLibrary() method searches for the library. The search performed by loadLibrary() depends on the system you are running on, but typically, it searches the directories listed in one of your environment variables set up to that purpose.
You can explicitly specify your absolute path.
Apart from system independence, there are no real differences security wise.
References :
1) https://security.stackexchange.com/questions/35724/security-implications-of-javas-system-load-vs-system-loadlibrary
2) https://www.chilkatsoft.com/java-loadLibrary-Linux.asp
Related
I am writing an interface in Java which uses underneath library in "C".
Now, when I try to load the library specifying relative path, it cannot find the library.
If I give the absolute path, it works fine.
I want to know, is there something to do with relative and absolute path on MAc OS. Because same code works well on linux(even though I specify relative path on that).
Please Help.
Defining the system property jna.debug_load (pass -Djna.debug_load=true to your JVM) will result in console output indicating where JNA is looking for your native library.
Keep in mind you need to define jna.library.path to be the directory where JNA can find your library. That value should be an absolute path. If you're using something like myapp/libs then your operation is going to be dependent on whatever the process's current directory is set to.
We have an app that sometimes is installed with an associated app. Both may be installed separately, at different times, and neither is usually in the OS Path environment setting.
IF both apps are installed, the one I'm working on needs to use a JNI library from the other app. This library uses a dozen or so other native libs. While I can FIND the JNI lib, I can't seem to find a way to use it without requiring the user to change their system setup.
I've found the (hacky) technique to add the JNI lib to the java.library.path, I've been unable to find any way of updating the native Path so the JNI lib can find it's associated libs.
The only things that have worked so far are to:
Add the folder that the JNI and associated files are in to the OS path before launching our app.
Launch our app so the Current Working Directory is the JNI lib folder.
Neither of which makes for a hassle-free user experience.
So, is there any way for a Java app to modify it's own environment Path so the JNI lib can find it's associated native libs? (currently testing on Win7, will also need to support OS/X)
This can not be done with an unknown location at run time. According to jni documentation
"To load your shared native library module in Java, simply use Java's System.loadLibrary method in a Java class:"
as well as
"Another common reason for the native library not loading is because it is not in your path. On Windows make sure the path environment variable contains the path to the native library. On Unix make sure that your LD_LIBRARY_PATH contains the path to the native library. Adding paths to LD_LIBRARY_PATH can slow down other programs on your system so you may want to consider alternative approaches. For example you could recompile your native library with extra path information using -rpath if you're using GNU, see the GNU linker documentation (ld man page). You could use a command such as ldconfig (Linux) or crle (Solaris) to add additional search paths to the default system configuration (this requires root access and you will need to read the man pages)."
So thus you need to know the location and must be in a path to be able to load the file. If the location is not known it can not be done due to how jni works and the jvm works.
One way to load a JNI lib with dependent libraries is to load each of the dependents then load the JNI library.
For example, if bar.so is dependent on foo.so and both libraries exist in /some/dir, do the following:
System.load("/some/dir/foo.so");
System.load("/some/dir/bar.so");
Use System.load() instead of System.loadLibrary() so you can specify the absolute path to the library.
You'll have to load all dependents of all loaded libraries unless they can be found in the java.library.path path.
Hope this helps.
The System.loadLibrary("Something") will load libSomething.so or Something.dll depending on platform. It will search for it in a list of directories (java.library.path) and will load the first it finds (I think).
I would like to know the full path of the loaded .so / .dll. There is ClassLoader.findLibrary(String libname) which does exactly what I want, but it is protected.
A workaround option could be to use System.mapLibraryName(String) to make platform specific file name from the library name and then to split and iterate through the java.library.path system property. I suppose it would give the same result as ClassLoader.finLibrary for most cases, but would it for all cases?
Is there any best practice for this task?
If adding user-defined library in Eclipse, one has an ability to set "Native library location". This field allows to enter some directory path.
When does this path plays a part?
Eclipse uses this information to build the java.library.path when it launches a Java program.
Background: Some Java frameworks depend on native code. This code usually comes in the form of a native shared library (*.so, *.dll). In Java, you can see methods with the attribute native. The code will load the shared library using System.loadLibrary().
In order to make the code independent of absolute paths, you just pass the name of the shared library to System.loadLibrary(). The System property java.library.path is then used to determine in which directories the VM should look to locate the file.
Together with Eclipse's feature to define user libraries, you can easily add Java libraries that depend on native code to your projects.
Are you referring to the Java Build Path configuration?
You may need this location if your project uses JNI or JNA. This directory is the location of native code (e.g. a Windows DLL written in C.)
I don't think this information is actually required until you try to run the code. You could provide this information via the Run Configuration for example.
Example: I have two shared objects (same should apply to .dlls). The first shared object is from a third-party library, we'll call it libA.so. I have wrapped some of this with JNI and created my own library, libB.so. Now libB depends on libA.
When webstarting, both libraries are places in some webstart working area. My java code attempts to load libB. At this point the system loader will attempt to load libA which is not in the system library path (java.library.path won't help this). The end result is that libB has an unsatisfied link and cannot be used.
I have tried loading libA before libB, but that still does not work. Seems the OS wants to do that loading for me. Is there any way I can make this work other than statically compiling?
I'm not sure if this would be handled exactly the same way for webstart, but we ran into this situation in a desktop application when dealing with a set of native libraries (dlls in our case).
Loading libA before libB should work, unless one of those libraries has a dependency that is unaccounted for and not in the path. My understanding is that once it gets to a system loadLibrary call (i.e. Java has found the library in its java.library.path and is now telling the OS to load it) - it is completely dependent on the operating system to find any dependent libraries, because at that point it is the operating system that is loading the library for the process, and the OS only knows how to look in the system path. That seems hard to set in the case of a Webstart app, but there is a way around this that does not involve static compiling. You may be able to shuffle where your libraries are - I am unsure
If you use a custom classloader, you can override loadLibrary and findLibrary so that it can locate your libraries from within a jar in your classpath, and if you also make it aware of your native library dependencies (i.e. libB depends on libA depends on libX, then when loading libB you can catch yourself and ensure you load libA first, and in checking that notice and load libX first. Then the OS doesn't try to find a library that isn't in your path. It's klunky and a bit painful, but ensuring Java finds them and loads them all in the correct order can work.
Static compilation proved to be the only way to webstart multiple dependent native libraries.
Are both native libraries packaged into a signed jar which is listed as
<nativelib ...>
In the JNLP file?