【问题标题】:Java Web Start - load native dependency with another native dependencyJava Web Start - 使用另一个本机依赖项加载本机依赖项
【发布时间】:2013-07-21 20:20:04
【问题描述】:

我正在使用 Java Web Start 来启动依赖于某些第三方本机库的 Java 应用程序。这些原生库随后会使用 LoadLibrary/dlopen 加载另一个原生库 (commonLib) 作为它们的依赖项。

当不使用 Web Start 时,当本机库位于同一目录中时,一切都会按预期工作。

然而,Web Start 需要将本机库打包在一个 jar 文件中并在 jnlp 文件中引用,我这样做了:

  <!-- Windows OS -->
    <resources os="Windows">
        <nativelib href="native/native-windows.jar" />
    </resource>

  <!-- Linux OS -->
    <resources os="Linux">
        <nativelib href="native/native-linux.jar" />
    </resources>

  <!-- Mac OSX -->
    <resources os="Mac OS X">
        <nativelib href="native/native-osx.jar"/>   
    </resources>

本机库加载正常,但无法加载其依赖项commonLib - C++ LoadLibrary/dlopen 调用失败,因为该文件存在于某个 jar/cache 文件夹中,而不是当前库搜索路径。

在 Windows 上,我可以通过在尝试加载 JNI 库之前在 Java 中预加载 commonLib 来解决这个问题,如下所示:

System.loadLibrary("commonLib");
System.loadLibrary("myNativeLib");

但是,这种方法在 OS X 上不起作用 - 本机代码中的 dlopen 失败。如果库已经加载,dlopen 显然不够聪明,不会尝试再次加载库。

是否有跨平台的方式来打包和加载依赖于 Java Web Start 中其他本机库的本机库?

【问题讨论】:

  • 罐子里是否包含所有相关的本地人?
  • 是的,请仔细检查。

标签: java java-web-start java-native-interface


【解决方案1】:

我能够找到一个(丑陋的)解决方法。诀窍是将依赖库(commonLib)打包到一个简单的资源 jar 中,并将其添加到 jnlp 文件中:

...
<resources os="Windows">
  <jar href="native/deps-windows.jar" />
</resources>
<resources os="Linux">
  <jar href="native/deps-linux.jar" />
</resources>
<resources os="Mac OS X">
  <jar href="native/deps-osx.jar" />
</resources>
...

第二步是使用 Java 将这些资源提取到一个临时目录中:

String tmpDir = System.getProperty("java.io.tmpdir");
if (!tmpDir.endsWith("/") && !tmpDir.endsWith("\\"))
    tmpDir += "/";
String resource = "commonDir.dll"; // Adjust accordingly to current OS, omitted for brevity
InputStream is = loader.getResourceAsStream(resource);
if (is == null) {
    // Handle error - resource not found
    return;
}
try {
    FileOutputStream os = new FileOutputStream(tmpDir + resource);
    byte[] buffer = new byte[1024*1024];
    int len = is.read(buffer);
    while (len != -1) {
        os.write(buffer, 0, len);
        len = is.read(buffer);
    }
    os.close();
    is.close();
    System.out.println("Extracted " + resource + " to " + tmpDir);
} catch(IOException ex) {
    // Handle the exception - cannot write to temp directory
    System.out.println("Could not extract resource " + resource + " to " + tmpDir + ": " + ex.getMessage());
}

第 3 步要么通知本地 JNI 库提取依赖项的完整路径,要么将当前目录临时设置为临时目录 tmpDir,加载 JNI 库并将其设置回来。这本身就是一个问题——在 Java 中很难改变当前的工作目录。您可以通过创建另一个小型实用 JNI 库来解决它,尽管 [1] 使用 C 执行此操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-08
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多