问题描述
我正在使用Java Web Start启动依赖于某些第三方本机库的Java应用程序.然后,这些本机库使用LoadLibrary/dlopen加载另一个本机库(commonLib
)作为它们的依赖项.
I am using Java Web Start to launch a Java application that depends on some third party native libraries. These native libraries then subsequently load another native library (commonLib
) as their dependency using LoadLibrary/dlopen.
当不使用Web Start时,当本机库位于同一目录中时,一切都会按预期进行.
When not using Web Start, everything works as expected when the native libraries are located in the same directory.
但是,Web Start要求将本机库打包在jar文件中,并在jnlp文件中引用,这是我做的:
Web Start, however, requires the native libraries to be packed in a jar file and referenced in the jnlp file, which I did:
<!-- 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文件夹中.
The native libraries load fine but they fail to load their dependency commonLib
- the C++ LoadLibrary/dlopen call fails because the file is present in some jar/cache folder not on the current library search path.
在Windows上,我能够通过在尝试加载JNI库之前在Java中预加载commonLib
来解决此问题,如下所示:
On Windows, I was able to solve this problem by pre-loading commonLib
in Java before trying to load the JNI library, like so:
System.loadLibrary("commonLib");
System.loadLibrary("myNativeLib");
但是,这种方法在OS X上不起作用-本机代码中的dlopen失败. dlopen显然不够聪明,如果已经加载库,就不要尝试再次加载该库.
However, this approach doesn't work on OS X - dlopen in the native code fails. dlopen is apparently not smart enough not to try to load the library again if it is already loaded.
是否存在跨平台的方式来打包和加载依赖于Java Web Start中其他本机库的本机库?
Is there a cross-platform way to pack and load native libraries that depend on other native libraries in Java Web Start?
推荐答案
我能够找到一种(丑陋的)解决方法.技巧是将依赖库(commonLib
)打包到一个简单的资源jar中,并将其添加到jnlp文件中:
I was able to find an (ugly) workaround. The trick is to pack the dependent libraries (commonLib
) to a simple resource jar and add it to the jnlp file:
...
<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将这些资源提取到一个临时目录中:
Step two is to extract these resources using Java into a temporary directory:
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库通知所提取依赖项的完整路径,或者将当前目录临时设置为temp目录tmpDir
,加载JNI库并将其重新设置.这本身就是一个问题-在Java中,很难更改当前的工作目录.您可以通过创建另一个小型实用程序JNI库(通过[ 1 ].
Step 3 is either to inform the native JNI library about the full path to the extracted dependency, or to temporarily set current directory to the temp directory tmpDir
, load the JNI library and set it back. This is a problem by itself - in Java it is hard to change the current working directory. You may solve it by creating another small utility JNI library that does that from C though [1].
这篇关于Java Web Start-用另一个本地依赖项加载本地依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!