在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"); 
} 
+0

您正在使用哪种OSGi实现? – omerkudat 2009-09-04 21:15:26

+0

我正在使用Equinox(规范R4) – 2009-09-04 21:39:30

+0

您可能想指出您使用的是哪个版本的Java,因为我以前从未遇到过JNA,它不是Java的一部分,包括6在内。 – SteveD 2009-09-07 11:11:26

问题是专门的JNA loadLibrary调用,它不是OSGi知道的。当你从OSGi包中调用loadLibrary时,它将使用OSGi类加载器(它是捆绑包感知的)来查找DLL的位置,在这种情况下,从捆绑包中提取出来,并通过System.loadLibrary()打电话给特定的地点。因为这个JNA似乎是(a)没有OSGi意识到的,(b)superflous,为什么不直接使用System.loadLibrary()而不是?

如果您需要同时写入,则在BundleActivator的bundle的start()方法中执行System.loadLibrary(),这会将本机库带入(您可能希望确保它不能在任何情况下,捆绑包都不能启动)。

+0

最终,JNA必须调用其自己的Native.loadLibrary或Native.register(在跟踪调试器后遵循相同的事件序列),以启用JNA提供的接口驱动或直接本地访问。我发现这个解决方案虽然看起来不太令人满意,但首先要像调用你的建议那样调用System.loadLibrary,然后在适当的地方调用Native.loadLibrary或Native.register。 – 2009-09-07 22:05:39

+0

你可能会发现这个工程在Windows上,但也许不在其他平台上。我记得一个问题,即在Windows上加载具有依赖关系的DLL(通过首先加载A,然后B加载B依赖于A),但在Mac上遇到问题。我不知道为什么可能会是这种情况......但只是警告您可能在您手中有一个特定于平台的解决方案。至少,您应该测试(而不是假设)非Windows平台。 – AlBlue 2009-09-08 21:17:09

+0

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 

和负载罐子作为常规库。

+0

我不确定这是一种可行的方法,我需要将DLL作为本地库加载,并且已经确定它是打包为试图使用它的OSGi包的一部分。 – 2009-09-04 14:43:41

+0

我在JNLP中使用这个tecnhique来加载本地库。 jvm可以在罐子里找到原生库lib – 2009-09-04 16:03:59

+0

所以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()它应该在包中找到本地库。

+0

这涉及到应用程序的打包和分发问题,将本机放置在应用程序的可预测位置,并使用“jna.library.path”将注入合成到JVM属性中。 – whatnick 2011-07-06 13:34:27