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

发布于 2024-08-04 00:05:56 字数 1729 浏览 6 评论 0原文

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

我通过另一个包提供了 JNA (导出 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 测试程序的一部分与之对话的 DLL。

编辑 2:将此代码添加到调用库的类中似乎允许 JNA 找到该库(当稍后调用 Native.loadLibrary 时)。看来我应该能够根据清单中的 Bundle-NativeCode 指令避免此调用。显然,一旦加载库, Native.loadLibrary 就会获取它的现有实例,但我不想依赖这种特定于订单的策略。

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

OSGi cannot find my DLL file, and I can't seem to figure out why.

Currently I have the DLL file (foo.dll) at the root of my bundle, I've also tried having it in a libs directory.

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):

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

// ...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.).

I've also tried specifying Bundle-NativeCode: /foo.dll.

Also of interest, these are the relevant OSGi properties (which I pulled up using 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.

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小嗷兮 2024-08-11 00:05:56

问题在于专门的 JNA loadLibrary 调用,它不被 OSGi 识别。当您从 OSGi 捆绑包调用 loadLibrary 时,它将使用 OSGi 类加载器(捆绑包感知)来查找 DLL 的位置,在这种情况下,将其从捆绑包中提取出来并使其可通过 System.loadLibrary() 加载。针对特定位置进行呼叫。

既然这个 JNA 似乎 (a) 不支持 OSGi,并且 (b) 多余,为什么不直接使用 System.loadLibrary() 呢?

如果您需要同时编写这两个内容,请在 BundleActivator 中的包的 start() 方法中执行 System.loadLibrary(),这将引入本机库(您可能希望确保如果无法加载该包,则该包无论如何都无法启动)。

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.

Since this JNA seems to be (a) not OSGi aware, and (b) superflous, why not just use System.loadLibrary() instead?

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

日久见人心 2024-08-11 00:05:56

查看 JNA 的文档,它指出:

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

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

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

Looking at JNA's documentation, it states:

  • 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 to java.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, and DYLD_LIBRARY_PATH on 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.

狼亦尘 2024-08-11 00:05:56

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

jar cvf foo.dll.jar foo.dll

并将 jar 作为常规库加载。

I suggest you try to package the dll as a jar:

jar cvf foo.dll.jar foo.dll

and the load the jar as a regular lib.

月棠 2024-08-11 00:05:56

最好将 com.sun.jna 包放在 org.osgi.framework.system.packages.extra 列表中,因为本机库(例如 <由 com.sun.jna.Native 内部使用的 code>jnidispatch.dll)只能加载一次,而 OSGi 类加载器可以多次加载类。

It's a good idea to have the com.sun.jna packages in your org.osgi.framework.system.packages.extra list, because the native libraries (such as jnidispatch.dll used internally by com.sun.jna.Native) can only be loaded once, whereas OSGi classloaders can load classes multiple times.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文