【问题标题】:Load DLL (using JNA) inside an OSGi bundle在 OSGi 包中加载 DLL(使用 JNA)
【发布时间】:2010-11-25 10:08:33
【问题描述】:

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

我通过另一个包(导出 com.sun.jna 和上面导入的其他包)提供了 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 实现?
  • 我正在使用 Equinox(规格 R4)
  • 您可能想说明您使用的是哪个版本的 Java,因为我以前从未遇到过 JNA,而且它不是 Java 的一部分,包括 6。
  • System.loadLibrary() 调用有效,因为它将调用类加载器的 findLibrary() 方法,如果它是 ClassLoader 的 Eclipse 实现,将通过查看包内部找到“本地”库。
  • 当你遇到这些讨厌的问题时,不要害怕调试这些类加载器和系统调用,这可能很有教育意义。

标签: java osgi jna


【解决方案1】:

org.osgi.framework.system.packages.extra 列表中包含com.sun.jna 包是个好主意,因为本机库(例如com.sun.jna.Native 内部使用的jnidispatch.dll)只能加载一次,而OSGi 类加载器可以加载类多次。

【讨论】:

    【解决方案2】:

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

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

    如果你需要两者都写,那么在BundleActivator中的bundle的start()方法中执行一个System.loadLibrary(),这将把原生库带进来(你可能要确保如果它不能被加载,在任何情况下都无法启动捆绑包)。

    【讨论】:

    • 最终,JNA 必须调用其自己的 Native.loadLibrary 或 Native.register(在使用调试器跟踪之后遵循相同的事件序列),以启用 JNA 的接口驱动或直接本机访问提供。我发现解决方案,尽管看起来并不令人满意,但首先按照您的建议调用 System.loadLibrary,然后在适当的位置调用 Native.loadLibrary 或 Native.register。
    • 您可能会发现这适用于 Windows,但可能不适用于其他平台。我记得一个问题,即加载具有依赖关系的 DLL 在 Windows 上工作(首先加载 A,然后 B,当 B 依赖于 A 时),但在 Mac 上存在问题。我不知道为什么会这样......但只是警告你可能有一个特定于平台的解决方案。至少,您应该针对非 Windows 平台进行测试(而不是假设)。
    • System.loadLibrary 使用 OSGi 类加载器——为了定位 DLL,Manifest 中的 Bundle-NativeCode 语句是绝对必要的——因此无论操作系统如何,此解决方案都会找到本机代码。如果 foo.dll 依赖于 bar.dll,那么按顺序加载它们将变得非常重要,但这是另一个问题,幸运的是这里不是这种情况。不过,感谢您的提醒。
    • 我遇到了同样的问题并想出了一个解决方案。正如 JNA 文档所述“使您的本机库在您的类路径中可用,在路径 {OS}-{ARCH}/{LIBRARY} 下,其中 {OS}-{ARCH} 是 JNA 的本机库的规范前缀(例如 win32-x86linux-amd64darwin)。如果资源位于 jar 文件中,加载时会自动提取。”因此,在包的根目录下创建一个文件夹(假设类路径包含该文件夹),命名为 darwin 并将库放在那里。在 macOS 上使用 JNA 4.1.0 和 Eclipse 插件中的库进行测试。
    【解决方案3】:

    查看 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 属性中。跨度>
    【解决方案4】:

    我建议你尝试将dll打包成jar:

    jar cvf foo.dll.jar foo.dll
    

    并将 jar 作为常规库加载。

    【讨论】:

    • 我不确定这是一种可行的方法,我需要将 DLL 作为本机库加载,并且已经确定它已打包为尝试使用它的 OSGi 捆绑包的一部分。
    • 我在 JNLP 中使用这种技术来加载本机库。 jvm 可以在 jars 中找到本地库
    • 所以 FWIW 我试过了,但没有用。我构建了 foo.jar 并将其添加到我的类路径(添加行:Bundle-ClassPath: libs/foo.jar, . )到上面的清单中,但仍然找不到该库。问题不仅仅在于 JVM 无法看到它,还需要通过 OSGi 路径/类加载器来加载它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多