理系学生日記

おまえはいつまで学生気分なのか

Javaアプリから共有ライブラリが読み込めない問題(java.library.path と LD_LIBRARY_PATH)

なんか良くわからないエラー (no [ライブラリ名] in java.library.path みたいなヤツ) が出てきたのだけれど、解決方法が java.library.path の設定ではなく、LD_LIBRARY_PATH の設定だったりした。この手のエラーに苦しめられ続けており、そのあたり、ちょっと掘り下げてみる。

java.library.path

java.library.path がどこで使われているかというと、ClassLoader で使われている。 実際、ClassLoader#findLibrary の JavaDoc には

ネイティブ・ライブラリの絶対パス名を返します。VMは、このメソッドを呼び出して、このクラス・ローダーによってロードされたクラスのネイティブ・ライブラリを検索します。このメソッドがnullを返す場合、VMは「java.library.path」プロパティで指定されたパスに従ってライブラリを検索します。

という記述がある。

具体的に ClassLoader のソースを見てみると、

    // Invoked in the java.lang.Runtime class to implement load and loadLibrary.
    static void loadLibrary(Class<?> fromClass, String name,
                            boolean isAbsolute) {
        ClassLoader loader =
            (fromClass == null) ? null : fromClass.getClassLoader();
        if (sys_paths == null) {
            usr_paths = initializePath("java.library.path");
            sys_paths = initializePath("sun.boot.library.path");
        }

というように、java.library.path を参照していることがわかる。 この java.library.path の値は、実際に読み込むライブラリ名と合成された後、JVM からロードされる。

LD_LIBRARY_PATH

LD_LIBRARY_PATH 自体は、Java の用語ではなく、Linux 系の用語である。 これが出てくる文脈は、ライブラリの動的ロードあるいは動的リンクで、内容としてはこのあたりが詳しい。

動的リンクとは実行時にライブラリがメモリ上にない場合に Linux に当該ライブラリをロードさせること、動的ロードとは、アプリケーションがライブラリ内の関数を動的に呼び出すことを指すらしいが、このときのライブラリの探索パスが LD_LIBRARY_PATH 環境変数になる。

なぜ java.library.path の設定では解消しなかったか

java.library.path はあくまで、JVM から見えるライブラリの探索パスになる。このため、このライブラリが他のライブラリに依存(動的リンクあるいは動的ロードの対象としている)場合、java.library.path の設定では効果を及ぼさず、この動的リンク/動的ロードに失敗してしまう。 こういうケースにおいては、LD_LIBRARY_PATH を設定しないといけない。