We have some proprietary libraries we need to interface with. These libraries are Windows DLLs, or Linux .so files. We got the headers to define the interfaces. Since I have never done anything with native libs, I looked at JNAerator (http://code.google.com/p/jnaerator/) and the BridJ and JNA stuff.
What's a simple way to use a C++ header file and the compiled lib to generate an interface? For example, by adopting JNA in general with something like:
SomeDLL lib = (SomeDLL) Native.loadLibrary("some_dll", SomeDLL.class);
I have to keep the DLL somewhere: how do I bundle the DLL with the Jar? I use Maven to build the Jar file... but the Native.loadLibrary interface doesn't allow to directly specify a path.
JNI coding is usually a manual process of writing C++ code to create the native glue methods. There's an entire book that explains it.
In some cases, http://jna.java.net/ can automate or accelerate this process, but don't count on it.
You can't 'bundle the native libraries' unless you go down the path of using OSGi or something like the Tanukisoft packaging tool, there's no built-in feature for that purpose in Java.
You connect the dots by using -Djava.library.path to tell java where to find native libraries, or using the lower-level APIs to System.loadLibrary that allow you to specify a full path.
Watch out for interactions with PATH and LD_LIBRARY_PATH if your native libraries have dependencies in turn.
With BridJ, you can bundle the DLL/.so/.dylib just fine with the JAR, but you have to put it (or them) in a specific platform-dependent path within the JAR, which starts by "org/bridj/lib/" and ends with a platform+architecture identifier.
Here's BridJ's own source tree, which exhibits this native bundling scheme :
org/bridj/lib resource directory
If you stick to this convention, you won't have do deal with PATH, LD_LIBRARY_PATH or file extraction : BridJ.register() (called on a #Library-annotated class with native methods) will do it all for you !
Related
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.
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.
I am using mediainfo (http://mediainfo.sourceforge.net/en) to extract information from audio and video files using Java code.
My java project runs over all platforms (osx, win & linux). So far I have only tested mediainfo over osx where the procedure is simple: just put libmediainfo.dylib in the target folder and access it using a native library and you're good to go. And the solution works flawlessly...
I am now looking to expand this functionality to the other OSs, starting with Linux. However, it is proving to be more of a challenge than I thought.
At first I kept getting this:
"java.lang.UnsatisfiedLinkError: Unable to load library 'mediainfo': libmediainfo.so: cannot open shared object file: No such file or directory"
and this was expected as it was looking in /usr/lib
but this was solved by installing the suitable libmediainfo0 & libzen0 ".deb from http://mediainfo.sourceforge.net/en/Download/Ubuntu
Still, my solution needs to be portable, meaning, I want all necessary resources to be included with the java project package without requiring any further installations.
I also need to know if it's possible to change mediainfo to look for the resources in my java package instead of a system location.
For your reference, I am using Java Native Access (jna) to interact with the library. Also using the MediaInfo.java & MediaInfoLibrary.java classes that the website suggests.
Let me know if you need other details.
any wisdom is highly appreciated
thanks!!
The latest release of JNA (3.5.2) will automatically unpack native libraries bundled as resources (whether file- or jar-based).
If you include you shared library for linux/amd64 as /linux-x86-64/libmylibrary.so in one of your jar files, JNA will extract it and load it automatically when you call Native.loadLibrary("my library"). Older versions of JNA require that you make the library available on LD_LIBRARY_PATH (envariable) or jna.library.path (system property).
I have an app(for CentOs) that uses two custom made shared libraries "libMyInit.so" (linked with libMyInit.so.1 and libMyInit.so.1.0.1) and libMyUtil.so (linked with libMyUtil.so.1 and libMyUtil.so libMyUtil.so.1.0.1). Thes are present inside the app packaging like MyApp/bin/libMyInit.so & MyApp/bin/util/libMyUtil.so along with their respective linked libraries.
When I have to run the app I have to explictly add the above mentioned paths to LD_LIBRARY_PATH without which it give the error like:
ERROR:Unable to load native MyUtil library. Reason: no MyUtil in java.library.path.
Is there any way I can avoid the manual adding of libraries to LD_LIBRARY_PATH ?
Something that I can do at compile time of shared libraries or later so that the custom made .so libraries are found in the java.library.path ?
IMHO the best way of doing this, is to use a custom System.loadLibrary in the static part of your classes. Have a look at my Java portaudio bindings here#github, especially at the LoadLibrary and JPA classes.
The LoadLibrary class selects a native library based on OS type and architecture, unpacks the lib from its JAR into the temp folder and loads it from there.
JPA now just has to call LoadLibrary.load and everything works automagically on all supported OSs and you only need one single JAR file.
One of the ways is to copy those libraries to one of /usr/lib, /lib, /usr/local/lib directories.
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?