3

Javaアプリケーションに自分のネイティブライブラリをロードしたい。これらのネイティブライブラリは、サードパーティのライブラリに依存しています(アプリケーションがクライアントコンピューターにインストールされている場合は、存在する場合と存在しない場合があります)。

私のJavaアプリケーション内で、依存ライブラリの場所を指定するようにユーザーに依頼します。この情報を取得したら、それを使用して、JNIコードを使用して「LD_LIBRARY_PATH」環境変数を更新します。以下は、「LD_LIBRARY_PATH」環境変数を変更するために使用しているコードスニペットです。

Javaコード

public static final int setEnv(String key、String value){
        if(key == null){
            新しいNullPointerException( "キーをnullにすることはできません");をスローします。
        }
        if(value == null){
            新しいNullPointerException( "値をnullにすることはできません");をスローします。
        }
        nativeSetEnv(key、value);を返します。
    }

public static final native int nativeSetEnv(String key、String value);

Jniコード(C)

    JNIEXPORT jint JNICALL Java_Test_nativeSetEnv(JNIEnv * env、jclass cls、jstring key、jstring value){
    const char * nativeKey = NULL;
    const char * nativeValue = NULL;
    nativeKey =(* env)-> GetStringUTFChars(env、key、NULL);
    nativeValue =(* env)-> GetStringUTFChars(env、value、NULL);
    int result = setenv(nativeKey、nativeValue、1);
    (ジント)結果を返します。
}

また、環境変数をフェッチするための対応するネイティブメソッドもあります。

LD_LIBRARY_PATHを正常に更新できます(このアサーションはCルーチンの出力に基づいています)getenv()

まだネイティブライブラリを読み込めません。依存するサードパーティライブラリはまだ検出されません。

ヘルプ/ポインタをいただければ幸いです。Linux64ビットを使用しています。

編集:

ダイナミックローダーが機能しているかどうかをテストするために、SSCE(C)を作成しました。これがSSCEです

#含む
#含む
#含む
#含む

int main(int argc、const char * const argv []){

    const char * constdependentLibPath = "...:";
    const char * const sharedLibrary = "...";
    char * newLibPath = NULL;
    char * originalLibPath = NULL;
    int l1、l2、結果;
    void*ハンドル=NULL;

    originalLibPath = getenv( "LD_LIBRARY_PATH");
    fprintf(stdout、 "\ n元のライブラリパス=%s \ n"、originalLibPath);
    l1 = strlen(originalLibPath);
    l2 = strlen(dependentLibPath);
    newLibPath =(char *)malloc((l1 + l2)* sizeof(char));
    strcpy(newLibPath、dependentLibPath);
    strcat(newLibPath、originalLibPath);
    fprintf(stdout、 "\ n新しいライブラリパス=%s \ n"、newLibPath);

    結果=setenv( "LD_LIBRARY_PATH"、newLibPath、1);
    if(result!= 0){
        fprintf(stderr、 "\n環境を更新できませんでした\n");
        exit(1);
    }    
    newLibPath = getenv( "LD_LIBRARY_PATH");
    fprintf(stdout、 "\ nenvからの新しいライブラリパス=%s \ n"、newLibPath);

    ハンドル=dlopen(sharedLibrary、RTLD_NOW);
    if(handle == NULL){
        fprintf(stderr、 "\ n共有ライブラリを読み込めませんでした:%s \ n"、dlerror());
        exit(1);        
    }
    fprintf(stdout、 "\n共有ライブラリが正常にロードされました。\n");

    結果=dlclose(handle);
    if(result!= 0){
        fprintf(stderr、 "\ n共有ライブラリをアンロードできませんでした:%s \ n"、dlerror());
        exit(1);
    }

    0を返します。
}

Cコードも機能しません。どうやら、ダイナミックローダーはLD_LIBRARY_PATH環境変数を再読み込みしていません。ダイナミックローダーにLD_LIBRARY_PATH環境変数を再読み込みさせる方法を理解する必要があります。

4

3 に答える 3

2

ここで受け入れられた答えを参照してください:

ctypesの実行時にLD_LIBRARY_PATHを変更する

言い換えれば、あなたがやろうとしていることは不可能です。更新されたLD_LIBRARY_PATHを使用して新しいプロセスを起動する必要があります(たとえば、 ProcessBuilderとupdateenvironment ()を使用して必要なディレクトリを連結します)

于 2011-04-29T22:52:06.407 に答える
2

これは、JVMのライブラリパスをプログラムで操作するために使用されるハックです。注:ClassLoader実装の内部に依存しているため、すべてのJVM/バージョンで機能するとは限りません。

String currentPath = System.getProperty("java.library.path");
System.setProperty( "java.library.path", currentPath + ":/path/to/my/libs" );

// this forces JVM to reload "java.library.path" property
Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null );

このコードは、UNIXスタイルのファイルパス区切り文字('/')とライブラリパス区切り文字(':')を使用します。これを行うクロスプラットフォームの方法については、システムプロパティを使用してシステム固有のセパレータを取得します。http://download.oracle.com/javase/tutorial/essential/environment/sysprop.html

于 2011-04-30T00:02:21.637 に答える
0

CollabNet Subversion Edgeに似たようなものを正常に実装しました。これは、すべてのオペレーティングシステムのSIGARライブラリに依存しています(32ビットと64ビットの両方でWindows / Linux / Sparcをサポートしています)...

Subversion Edgeは、Webコンソールを介してSubversionリポジトリを管理するのに役立つWebアプリケーションであり、SIGARを使用してSIGARライブラリを使用すると、OSから直接ユーザーにデータ値を提供できます...プロパティ「java.library」の値を更新する必要があります。実行時のパス」。(https://ctf.open.collab.net/integration/viewvc/viewvc.cgi/trunk/console/grails-app/services/com/collabnet/svnedge/console/OperatingSystemService.groovy?revision=1890&root=svnedge&system=exsy1005&view = markup URLはGroovyコードですが、ここでJavaに変更したことに注意してください)...

次の例は、上記のURLでの実装です...(Windowsでは、ユーザーがライブラリをダウンロードした後、またはアプリケーションを使用してダウンロードした場合、ユーザーはマシンを再起動する必要があります)..."java.library。 path」は、システムパス「sys_paths」の代わりにユーザーのパス「usr_paths」を更新します(後者を使用する場合、OSによっては許可例外が発生する可能性があります)。

133/**
134 * Updates the java.library.path at run-time.
135 * @param libraryDirPath
136 */
137 public void addDirToJavaLibraryPathAtRuntime(String libraryDirPath) 
138    throws Exception {
139    try {
140         Field field = ClassLoader.class.getDeclaredField("usr_paths");
141         field.setAccessible(true);
142         String[] paths = (String[])field.get(null);
143         for (int i = 0; i < paths.length; i++) {
144             if (libraryDirPath.equals(paths[i])) {
145                 return;
146             }
147         }
148         String[] tmp = new String[paths.length+1];
149         System.arraycopy(paths,0,tmp,0,paths.length);
150         tmp[paths.length] = libraryDirPath;
151         field.set(null,tmp);
152         String javaLib = "java.library.path";
153         System.setProperty(javaLib, System.getProperty(javaLib) +
154             File.pathSeparator + libraryDirPath);
155 
156     } catch (IllegalAccessException e) {
157         throw new IOException("Failed to get permissions to set " +
158             "library path to " + libraryDirPath);
159     } catch (NoSuchFieldException e) {
160         throw new IOException("Failed to get field handle to set " +
161            "library path to " + libraryDirPath);
162     }
163 }

コンソールのBootstrapサービス(Groovy on Grailsアプリケーション)クラスは、サービスを実行し、ライブラリディレクトリへのフルパスで実行します... UNiXベースのサーバーは、ライブラリを取得するためにサーバーを再起動する必要はありませんが、Windowsボックスはインストール後にサーバーを再起動する必要があります。あなたの場合、あなたはこれを次のように呼ぶでしょう:

     String appHomePath = "/YOUR/PATH/HERE/TO/YOUR/LIBRARY/DIRECTORY";
     String yourLib = new File(appHomePath, "SUBDIRECTORY/").getCanonicalPath();
124  try {
125      addDirToJavaLibraryPathAtRuntime(yourLib);
126  } catch (Exception e) {
127      log.error("Error adding the MY Libraries at " + yourLib + " " +
128            "java.library.path: " + e.message);
129  }

アプリケーションを出荷するOSごとに、特定のプラットフォーム(32ビット-Linux、64ビット-Windowsなど)に一致するバージョンのライブラリを提供するようにしてください。

于 2011-04-30T01:54:23.107 に答える