OSGi cannot find my DLL file, and I can't seem to figure out why.
Currently I have the DLL file (foo.dll
) at the root of my bundle, I've also tried having it in a libs
directory.
The Manifest for the bundle in question looks something like this:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: foobundle
Bundle-SymbolicName: com.foo.bar
Bundle-Version: 1.0.0
Bundle-Vendor: me
Import-Package: com.sun.jna,
com.sun.jna.ptr,
com.sun.jna.win32
Export-Package: com.foo.bar
Bundle-NativeCode: foo.dll;
osname=WindowsXP;
processor=x86
Then in my JNA interface I perform a loadLibrary (as per the documentation):
public interface MyFooInterface extends com.sun.jna.Library{
static final MyFooInterface INSTANCE = (MyFooInterface)com.sun.jna.Native.loadLibrary("foo", MyFooInterface .class);
// specific interface defs here...
}
Then in another class I attempt to use the JNA interface
// ...code
int var = MyFooInterface.INSTANCE.bar();
// ...more code
I have JNA supplied via another bundle (which exports com.sun.jna and the other packages imported above), but have also tried packaging it with the bundle defined here (and added it to the classpath in that case, etc.).
I've also tried specifying Bundle-NativeCode: /foo.dll
.
Also of interest, these are the relevant OSGi properties (which I pulled up using getprop
)
org.osgi.framework.os.name=WindowsXP
org.osgi.framework.processor=x86
Even after all this (and with every trial I made) I always end up with the following error (and a stack trace not shown):
java.lang.UnsatisfiedLinkError: Unable to load library 'foo': The specified module could not be found.
...so what am I missing?
Edit: I should also note that I've tested and had success the JNA interface code and the DLL that it talks to as part of a JUnit Test program.
Edit 2: Adding this code to the class that's calling the library seems to allow JNA to find the library (when Native.loadLibrary
gets called later). It seems I should be able to avoid this call based on the Bundle-NativeCode directive in the Manifest. Clearly once the library is loaded Native.loadLibrary grabs the existing instance of it, but I'd prefer not to depend on this very order-specific tactic.
static{
System.loadLibrary("foo");
}
The problem is the specialised JNA loadLibrary call, which is not OSGi aware. When you invoke loadLibrary from an OSGi bundle, it will use the OSGi classloader (which is bundle aware) to find where the DLL is, and in this case, extract it out from the bundle and make it loadable via the System.loadLibrary() call against a specific location.
Since this JNA seems to be (a) not OSGi aware, and (b) superflous, why not just use System.loadLibrary() instead?
If you need to write both, then perform a System.loadLibrary() in the bundle's start() method in the BundleActivator, which will bring the native library in (you probably want to ensure that if it can't be loaded, the bundle can't be started in any case).
Looking at JNA's documentation, it states:
jna.library.path
system property to the path to your target library. This property is similar to java.library.path
but only applies to libraries loaded by JNA.PATH
on Windows, LD_LIBRARY_PATH
on Linux, and DYLD_LIBRARY_PATH
on OSX.So to get around this shortcoming you could resolve the the absolute path of the library and load that.
Assuming that its Eclipse's standard class loader, you can do ClassLoader.findLibrary()
which should find the local library in the bundle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With