2013-07-21 28 views
7

Java Web Startを使用して、サードパーティ製のネイティブライブラリに依存するJavaアプリケーションを起動しています。これらのネイティブライブラリは、その後、LoadLibrary/dlopenを使用して依存関係として別のネイティブライブラリ(commonLib)をロードします。Java Web Start - 他のネイティブ依存関係とのネイティブ依存関係のロード

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 - ファイルが現在のライブラリ検索パス上にないjar/cacheフォルダに存在するため、C++ LoadLibrary/dlopen呼び出しが失敗します。 Windowsでは

ので、同じように、私は、JNIライブラリをロードしようとする前にJavaでプリロードcommonLibすることにより、この問題を解決することができました:

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

しかし、このアプローチは、OS X上では動作しません。 - ネイティブコードのdlopenが失敗します。 dlopenはすでに読み込まれている場合にライブラリを再度ロードしようとしないほどスマートではないようです。

Java Web Startの他のネイティブライブラリに依存するネイティブライブラリをパックして読み込むためのクロスプラットフォームの方法はありますか?

+0

Jarsには、関係するすべてのネイティブが含まれていますか? –

+0

はい、それをダブルチェックしました。 –

答えて

1

私は(醜い)回避策を見つけることができました。トリックは単純なリソースジャーに依存ライブラリ(commonLib)をパックし、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> 
... 

ステップ2は、一時ディレクトリに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ライブラリに通知するか、現在のディレクトリをtempディレクトリに一時的に設定し、JNIライブラリをロードして戻します。これは単なる問題です.Javaでは、現在の作業ディレクトリを変更することは困難です。あなたは[1]でもCからそれを行うもう1つの小さなユーティリティのJNIライブラリを作成することで解決できます。