在OSGi包中加载DLL(使用JNA)

OSGi找不到我的DLL文件,我似乎无法弄清楚为什么。

目前我在我的bundle的根目录下有DLL文件( foo.dll ),我也试过在libs目录下使用它。

有问题的捆绑的清单看起来像这样:

 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 

然后在我的JNA界面中执行loadLibrary(根据文档):

 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... } 

然后在另一个类中我尝试使用JNA接口

 // ...code int var = MyFooInterface.INSTANCE.bar(); // ...more code 

我通过另一个包(它导出com.sun.jna和上面导入的其他包)提供了JNA,但是也尝试用这里定义的包打包它(在这种情况下将它添加到类路径中等)。

我也尝试过指定Bundle-NativeCode: /foo.dll

同样感兴趣的是,这些是相关的OSGi属性(我使用getprop

 org.osgi.framework.os.name=WindowsXP org.osgi.framework.processor=x86 

即使在所有这些(以及我所做的每一次试验)之后,我总是会遇到以下错误(并且未显示堆栈跟踪):

 java.lang.UnsatisfiedLinkError: Unable to load library 'foo': The specified module could not be found. 

……所以我错过了什么?

编辑 :我还应该注意,我已经测试并成功了JNA接口代码和它作为JUnit测试程序的一部分进行对话的DLL。

编辑2 :将此代码添加到调用库的类似乎允许JNA查找库( Native.loadLibrary调用Native.loadLibrary时)。 看来我应该能够根据Manifest中的Bundle-NativeCode指令来避免这个调用。 很明显,一旦加载了库,Native.loadLibrary会抓取它的现有实例,但我宁愿不依赖于这个特定于订单的策略。

 static{ System.loadLibrary("foo"); } 

问题是专门的JNA loadLibrary调用,它不是OSGi知道的。 当您从OSGi包调用loadLibrary时,它将使用OSGi类加载器(可识别bundle)来查找DLL的位置,在这种情况下,从包中提取它并通过System.loadLibrary()使其可加载打电话到特定地点。

由于这个JNA似乎是(a)不是OSGi意识到的,并且(b)超级丰富,为什么不直接使用System.loadLibrary()呢?

如果你需要同时写两个,那么在BundleActivator的bundle的start()方法中执行一个System.loadLibrary(),这将带来本机库(你可能想确保如果它无法加载,那么bundle在任何情况下都无法启动)。

查看JNA的文档,它指出:

  • 使您的目标库可用于Java程序。 有两种方法可以做到这一点:
    • 首选方法是将jna.library.path系统属性设置为目标库的路径。 此属性类似于java.library.path但仅适用于JNA加载的库。
    • 在启动VM之前更改相应的库访问环境变量。 这是Windows上的LD_LIBRARY_PATH ,Linux上的LD_LIBRARY_PATH和OSX上的DYLD_LIBRARY_PATH

因此,为了解决这个缺点,你可以解决库的绝对路径并加载它。

假设它是Eclipse的标准类加载器,您可以执行ClassLoader.findLibrary() ,它应该在bundle中找到本地库。

我建议你尝试将dll打包为jar:

 jar cvf foo.dll.jar foo.dll 

并将jar作为常规lib加载。