在OSGi包中加载DLL(使用JNA)
OSGi无法找到我的DLL文件,我似乎无法弄清楚为什么。在OSGi包中加载DLL(使用JNA)
目前我有我的软件包根目录下的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接口I进行调用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
我有JNA通过另一个外围设备提供le(导出com.sun.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测试程序的一部分与之对话。
编辑2:将此代码添加到调用该库的类似乎允许JNA找到库(稍后调用Native.loadLibrary
时)。看来我应该能够避免这个基于Manifest中的Bundle-NativeCode指令的调用。显然,一旦加载了库,Native.loadLibrary就会抓取它的现有实例,但我不想依赖这种特定于订单的策略。
static{
System.loadLibrary("foo");
}
问题是专门的JNA loadLibrary调用,它不是OSGi知道的。当你从OSGi包中调用loadLibrary时,它将使用OSGi类加载器(它是捆绑包感知的)来查找DLL的位置,在这种情况下,从捆绑包中提取出来,并通过System.loadLibrary()打电话给特定的地点。因为这个JNA似乎是(a)没有OSGi意识到的,(b)superflous,为什么不直接使用System.loadLibrary()而不是?
如果您需要同时写入,则在BundleActivator的bundle的start()方法中执行System.loadLibrary(),这会将本机库带入(您可能希望确保它不能在任何情况下,捆绑包都不能启动)。
最终,JNA必须调用其自己的Native.loadLibrary或Native.register(在跟踪调试器后遵循相同的事件序列),以启用JNA提供的接口驱动或直接本地访问。我发现这个解决方案虽然看起来不太令人满意,但首先要像调用你的建议那样调用System.loadLibrary,然后在适当的地方调用Native.loadLibrary或Native.register。 – 2009-09-07 22:05:39
你可能会发现这个工程在Windows上,但也许不在其他平台上。我记得一个问题,即在Windows上加载具有依赖关系的DLL(通过首先加载A,然后B加载B依赖于A),但在Mac上遇到问题。我不知道为什么可能会是这种情况......但只是警告您可能在您手中有一个特定于平台的解决方案。至少,您应该测试(而不是假设)非Windows平台。 – AlBlue 2009-09-08 21:17:09
System.loadLibrary使用OSGi类加载器 - Manifest中的Bundle-NativeCode语句对于查找DLL是绝对必需的 - 因此无论操作系统如何,此解决方案都会找到本机代码。如果富。DLL依赖于bar.dll,按顺序加载它们将变得非常重要,但这是另一个问题,幸运的是这里不是这种情况。尽管如此,感谢大家的支持。 – 2009-09-11 21:20:35
我建议你尝试打包DLL作为一个jar:
jar cvf foo.dll.jar foo.dll
和负载罐子作为常规库。
我不确定这是一种可行的方法,我需要将DLL作为本地库加载,并且已经确定它是打包为试图使用它的OSGi包的一部分。 – 2009-09-04 14:43:41
我在JNLP中使用这个tecnhique来加载本地库。 jvm可以在罐子里找到原生库lib – 2009-09-04 16:03:59
所以FWIW我试过了,没有什么好处。我构建了foo.jar,并将其添加到我的类路径中(将Bundle-ClassPath:libs/foo.jar, )添加到上面的Manifest中,但仍无法找到该库。这个问题源于JVM无法看到它,它需要通过OSGi路径/类加载器加载。 – 2009-09-04 16:54:02
看着JNA的文档,它指出:
- 让你的目标库提供给您的Java程序。有两种方法可以执行此操作:
- 首选的方法是将
jna.library.path
系统属性设置为目标库的路径。此属性与java.library.path
类似,但仅适用于由JNA加载的库。 - 在启动VM之前更改相应的库访问环境变量。这是Windows上的
PATH
,Linux上的LD_LIBRARY_PATH
和OSX上的DYLD_LIBRARY_PATH
。
- 首选的方法是将
因此,要解决这个缺点,你可以解决库的绝对路径和加载。
假设它的Eclipse的标准类加载器,你可以做ClassLoader.findLibrary()
它应该在包中找到本地库。
这涉及到应用程序的打包和分发问题,将本机放置在应用程序的可预测位置,并使用“jna.library.path”将注入合成到JVM属性中。 – whatnick 2011-07-06 13:34:27
您正在使用哪种OSGi实现? – omerkudat 2009-09-04 21:15:26
我正在使用Equinox(规范R4) – 2009-09-04 21:39:30
您可能想指出您使用的是哪个版本的Java,因为我以前从未遇到过JNA,它不是Java的一部分,包括6在内。 – SteveD 2009-09-07 11:11:26