Java 在OSGi包中加载DLL(使用JNA)
OSGi找不到我的DLL文件,我似乎不知道为什么 目前,我将DLL文件(Java 在OSGi包中加载DLL(使用JNA),java,osgi,jna,Java,Osgi,Jna,OSGi找不到我的DLL文件,我似乎不知道为什么 目前,我将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.s
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(根据文档):
然后在另一个类中,我尝试使用JNA接口
// ...code
int var = MyFooInterface.INSTANCE.bar();
// ...more code
我通过另一个bundle(导出com.sun.JNA和上面导入的其他包)提供了JNA,但也尝试使用这里定义的bundle对其进行打包(在这种情况下,将其添加到类路径中,等等)
我还尝试指定Bundle NativeCode:/foo.dll
同样有趣的是,这些是相关的OSGi属性(我使用getprop
)
即使在所有这些之后(以及在我进行的每一次尝试中),我总是会出现以下错误(并且没有显示堆栈跟踪):
…那么我错过了什么
编辑:我还应该注意,我已经测试了JNA接口代码和作为JUnit测试程序一部分与之对话的DLL,并取得了成功
编辑2:将此代码添加到调用库的类中似乎允许JNA查找库(稍后调用Native.loadLibrary
时)。基于清单中的Bundle NativeCode指令,我似乎应该能够避免这个调用。显然,一旦加载了库,Native.loadLibrary就会抓住它的现有实例,但我不希望依赖这种特定于顺序的策略
static{
System.loadLibrary("foo");
}
我建议您尝试将dll打包为jar:
jar cvf foo.dll.jar foo.dll
并将jar作为常规库加载。查看JNA的文档,它指出:
- 使目标库可用于Java程序。有两种方法可以做到这一点:
- 首选方法是将
系统属性设置为目标库的路径。此属性类似于jna.library.path
,但仅适用于JNA加载的库java.library.path
- 在启动VM之前,请更改相应的库访问环境变量。这是Windows上的
,Linux上的PATH
,OSX上的LD\u LIBRARY\u PATH
DYLD\u LIBRARY\u PATH
- 首选方法是将
假设它是Eclipse的标准类加载器,您可以执行
ClassLoader.findLibrary()
,它应该在包中找到本地库。问题在于专门的JNA loadLibrary调用,它不支持OSGi。当您从OSGi捆绑包调用loadLibrary时,它将使用OSGi类加载器(该类加载器可识别捆绑包)查找DLL所在的位置,在本例中,将其从捆绑包中提取出来,并通过System.loadLibrary()调用针对特定位置使其可加载
既然这个JNA看起来(a)不支持OSGi,而且(b)是超级库,为什么不直接使用System.loadLibrary()呢
如果您需要同时编写这两个文件,那么在BundleActivator的bundle的start()方法中执行System.loadLibrary(),这将引入本机库(您可能希望确保如果无法加载,则无论如何都无法启动该bundle)。我不确定这是一种可行的方法,我需要将DLL作为本机库加载,我已经确定它是作为试图使用它的OSGi包的一部分打包的。jvm可以在Jarso FWIW中找到本机lib,我试过了,但没有效果。我构造了foo.jar并将其添加到我的类路径中(这会将行:Bundle ClassPath:libs/foo.jar,)添加到上面的清单中,但仍然找不到库。问题不仅仅源于JVM无法看到它,还需要通过OSGi路径/类加载器加载它。您使用的是哪个OSGi实现?我使用的是Equinox(规范R4)您可能需要说明您使用的是哪个版本的Java,因为我以前从未见过JNA,而且它在6之前(包括6)都不是Java的一部分。System.loadLibrary()调用有效,因为它将调用类加载器的findLibrary()方法,如果它是类加载器的Eclipse实现,将通过查看捆绑包内部找到“本地”库。当您遇到这些严重问题时,不要害怕调试这些类加载器和系统调用,这可能非常有教育意义。最终,JNA必须调用自己的Native.loadLibrary或Native.register(使用调试器跟踪后,遵循相同的事件序列)为了启用JNA提供的接口驱动或直接本机访问。我发现解决方案(尽管看起来不太令人满意)是首先调用System.loadLibrary,正如您所建议的,然后在适当的位置调用Native.loadLibrary或Native.register。您可能会发现这在Windows上有效,但在其他平台上可能不起作用。我记得一个问题,即加载一个具有依赖项的DLL在Windows上工作(当B依赖于a时,先加载a,然后加载B),但在Mac上有问题。我不知道为什么会这样。。。但这只是一个警告,说明您手中可能有一个特定于平台的解决方案。至少,您应该测试(而不是假设)非Windows平台。System.loadLibrary使用OSGi类加载器——为了定位DLL,清单中的Bundle NativeCode语句是绝对必需的——因此,无论操作系统如何,此解决方案都会找到本机代码。如果foo.dll依赖于bar.dll,则按顺序加载它们将变得非常重要,但这是另一个问题,幸运的是,这里的情况并非如此。不过,谢谢你的提醒。我也遇到了同样的问题,并找到了解决办法。正如JNA文档所述,“在路径
{OS}-{ARCH}/{library}
下,使本机库在类路径上可用,wh
java.lang.UnsatisfiedLinkError: Unable to load library 'foo': The specified module could not be found.
static{
System.loadLibrary("foo");
}
jar cvf foo.dll.jar foo.dll