Java 在 OSGi 包中加载 DLL(使用 JNA)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1375550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Load DLL (using JNA) inside an OSGi bundle
提问by Mark Elliot
OSGi cannot find my DLL file, and I can't seem to figure out why.
OSGi 找不到我的 DLL 文件,我似乎无法弄清楚原因。
Currently I have the DLL file (foo.dll
) at the root of my bundle, I've also tried having it in a libs
directory.
目前foo.dll
,我的包的根目录中有 DLL 文件 ( ),我也尝试将其放在libs
目录中。
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):
然后在我的 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...
}
Then in another class I attempt to use the JNA interface
然后在另一个类中我尝试使用 JNA 接口
// ...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.).
我通过另一个包(导出 com.sun.jna 和上面导入的其他包)提供了 JNA,但也尝试使用此处定义的包打包它(并在这种情况下将其添加到类路径等)。
I've also tried specifying Bundle-NativeCode: /foo.dll
.
我也试过指定Bundle-NativeCode: /foo.dll
.
Also of interest, these are the relevant OSGi properties (which I pulled up using getprop
)
同样有趣的是,这些是相关的 OSGi 属性(我使用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.
编辑:我还应该注意,我已经测试并成功了 JNA 接口代码和它作为 JUnit 测试程序的一部分与之对话的 DLL。
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.
编辑 2:将此代码添加到调用库的类似乎允许 JNA 找到库(Native.loadLibrary
稍后调用时)。看来我应该能够根据 Manifest 中的 Bundle-NativeCode 指令避免这个调用。显然,一旦加载了库,Native.loadLibrary 就会获取它的现有实例,但我不希望依赖于这种特定于订单的策略。
static{
System.loadLibrary("foo");
}
采纳答案by AlBlue
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.
问题是专门的 JNA loadLibrary 调用,它不支持 OSGi。当您从 OSGi 包调用 loadLibrary 时,它将使用 OSGi 类加载器(可识别包)来查找 DLL 的位置,在这种情况下,从包中提取它并通过 System.loadLibrary() 使其可加载针对特定位置调用。
Since this JNA seems to be (a) not OSGi aware, and (b) superflous, why not just use System.loadLibrary() instead?
既然这个 JNA 似乎 (a) 不知道 OSGi,并且 (b) 多余,为什么不直接使用 System.loadLibrary() 呢?
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).
如果两者都需要写,那么在 BundleActivator 中 bundle 的 start() 方法中执行 System.loadLibrary() ,这将带入本机库(您可能希望确保如果无法加载,bundle在任何情况下都无法启动)。
回答by Miguel Ping
I suggest you try to package the dll as a jar:
我建议您尝试将 dll 打包为 jar:
jar cvf foo.dll.jar foo.dll
and the load the jar as a regular lib.
并将 jar 作为常规库加载。
回答by SteveD
Looking at JNA's documentation, it states:
查看 JNA 的文档,它指出:
- Make your target library available to your Java program. There are two ways to do this:
- The preferred method is to set the
jna.library.path
system property to the path to your target library. This property is similar tojava.library.path
but only applies to libraries loaded by JNA. - Change the appropriate library access environment variable before launching the VM. This is
PATH
on Windows,LD_LIBRARY_PATH
on Linux, andDYLD_LIBRARY_PATH
on OSX.
- The preferred method is to set the
- 使您的目标库可用于您的 Java 程序。有两种方法可以做到这一点:
- 首选方法是将
jna.library.path
系统属性设置为目标库的路径。此属性类似于java.library.path
但仅适用于 JNA 加载的库。 - 在启动 VM 之前更改适当的库访问环境变量。这是
PATH
在 Windows、LD_LIBRARY_PATH
Linux 和DYLD_LIBRARY_PATH
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.
假设它是 Eclipse 的标准类加载器,您可以ClassLoader.findLibrary()
在 bundle 中找到本地库。