web-dev-qa-db-ja.com

java.lang.UnsatisfiedLinkError no *****。dll in Java.library.path

Webアプリケーションにカスタムdllファイルをロードするにはどうすればよいですか?私は次の方法を試しましたが、失敗しました。

  • system32フォルダー内のすべての必要なdllをコピーし、それらのうちの1つをServletコンストラクターSystem.loadLibraryにロードしようとしました
  • Tomcat_home/shared/libおよびTomcat_home/common/libに必要なdllをコピーしました
  • これらのすべてのdllは、WebアプリケーションのWEB-INF/libにあります
84
Ketan Khairnar

System.loadLibrary()が機能するためには、ライブラリ(WindowsではDLL)がPATHのどこかにあるディレクトリにある必要がありますまたはJava.library.pathシステムプロパティにリストされているパスにあるため(Java Java -Djava.library.path=/path/to/dirのように)。

さらに、loadLibrary()には、最後に.dllを付けずに、ライブラリのベース名を指定します。したがって、/path/to/something.dllには、System.loadLibrary("something")を使用するだけです。

また、取得している正確なUnsatisfiedLinkErrorを確認する必要があります。次のような場合:

Exception in thread "main" Java.lang.UnsatisfiedLinkError: no foo in Java.library.path

PATHまたはJava.library.pathfooライブラリ(foo.dll)が見つかりません。次のような場合:

Exception in thread "main" Java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V

JavaがアプリケーションのネイティブJava関数を実際のネイティブの対応する関数にマップできないという意味で、ライブラリ自体に何か問題があります。

まず、System.loadLibrary()呼び出しの周りにログを記録して、適切に実行されるかどうかを確認します。例外をスローする場合、または実際に実行されるコードパスにない場合は、上記で説明したUnsatisfiedLinkErrorの後者のタイプを常に取得します。

補足として、ほとんどの人はloadLibrary()呼び出しをネイティブメソッドを使用してクラスの静的初期化ブロックに入れ、常に1回だけ実行されるようにします。

class Foo {

    static {
        System.loadLibrary('foo');
    }

    public Foo() {
    }

}
142
Adam Batkin

JVMによって一度だけ読み取られるため、実行時に「Java.library.path」変数を変更するだけでは十分ではありません。次のようにリセットする必要があります。

System.setProperty("Java.library.path", path);
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);

実行時のJavaライブラリパスの変更 で略奪してください。

13
Alexandre

Adam Batkinによる元の答えは解決策につながりますが、Webコンテナを再起動せずにWebアプリケーションを再デプロイすると、次のエラーが発生するはずです。

Java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
   at Java.lang.ClassLoader.loadLibrary0(ClassLoader.Java:1715)
   at Java.lang.ClassLoader.loadLibrary(ClassLoader.Java:1646)
   at Java.lang.Runtime.load0(Runtime.Java:787)
   at Java.lang.System.load(System.Java:1022)

これは、最初にDLLをロードしたClassLoaderがまだこのDLLを参照しているために発生します。ただし、webappは現在新しいClassLoaderで実行されており、同じJVMが実行されており、JVMは同じDLLへの2つの参照を許可しないため、reloadそれ。したがって、webappは既存のDLLにアクセスできず、新しいものをロードできません。だから...あなたは立ち往生しています。

TomcatのClassLoaderドキュメント 再ロードされたwebappが新しい分離されたClassLoaderで実行される理由と、この制限を(非常に高いレベルで)回避する方法の概要を説明します。

解決策は、Adam Batkinのソリューションを少し拡張することです。

   package awesome;

   public class Foo {

        static {
            System.loadLibrary('foo');
        }

        // required to work with JDK 6 and JDK 7
        public static void main(String[] args) {
        }

    }

次に、このコンパイル済みクラスだけを含むjarをTomcat_HOME/libフォルダーに配置します。

これで、webapp内で、Tomcatにこのクラスを参照させるだけで済みます。これは次のように簡単に実行できます。

  Class.forName("awesome.Foo");

これで、DLLが共通のクラスローダーにロードされ、再デプロイされた後でもwebappから参照できるようになります。

理にかなっていますか?

作業用の参照コピーは、Googleコード static-dll-bootstrapper にあります。

10
Matt M

System.loadLibraryが問題のDLLを見つけられないという問題の場合、よくある誤解(Javaのエラーメッセージによって強化された)の1つは、システムプロパティJava.library.pathが答えであるということです。システムプロパティJava.library.pathをDLLがあるディレクトリに設定すると、System.loadLibraryは実際にDLLを見つけます。ただし、多くの場合、DLLが他のDLLに依存している場合、依存するDLLのロードはオペレーティングシステムによって完全に管理されているため、Java.library.pathは役に立ちません。 Java.library.pathは何もありません。したがって、JVMを起動する前に、Java.library.pathをバイパスして、DLLのディレクトリをLD_LIBRARY_PATH(Linux)、DYLD_LIBRARY_PATH(MacOS)、またはPath(Windows)に追加することをお勧めします。

(注:私はDLLまたは共有ライブラリの一般的な意味で「DLL」という用語を使用しています。)

7
Ian Emmons

System.load()を使用して、それぞれのOSの標準ライブラリフォルダー内のファイルではなく、必要な絶対パスを指定できます。

既に存在するネイティブアプリケーションが必要な場合は、 System.loadLibrary(String filename) を使用します。独自のものを提供したい場合は、おそらくload()の方が良いでしょう。

Java.library.pathを正しく設定してloadLibraryを使用することもできるはずです。チェックされている両方のパスを示す実装ソースについては、 ClassLoader.Java を参照してください(OpenJDK)

7

既にあるディレクトリ(現在のディレクトリなど)に関連するファイルをロードする必要がある場合、簡単な解決策を次に示します。

File f;

if (System.getProperty("Sun.Arch.data.model").equals("32")) {
    // 32-bit JVM
    f = new File("mylibfile32.so");
} else {
    // 64-bit JVM
    f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());
3
Rick C. Hodgin

Java.lang.UnsatisfiedLinkError: no pdf_Java in Java.library.pathを探している人向け

私は同じ例外に直面していました。私はそれを機能させるためにすべてと重要なことを試しました:

  1. Pdf lib.jarの正しいバージョン(私の場合、サーバーランタイムに保持されているバージョンjarが間違っていました)
  2. フォルダーを作成し、その中にpdflib jarを保持し、PATH変数にフォルダーを追加します

Tomcat 6で動作しました。

2

かわいそう!体がこの問題を再現する場合、ここでそれを書き留めます。

Adamが提案したようにロードしようとしましたが、AMD64対IA 32の例外に巻き込まれていました。 JREとJDKは64ビットであり、クラスパスに正しく追加しました。

私の実際の例はここにあります: nstatisfied link error

2
sayannayas
  1. ネイティブlibのパスを%PATH%に追加したと思われる場合は、次の方法でもう一度テストしてください。

    System.out.println(System.getProperty( "Java.library.path"))

DLLが%PATH%上にある場合、実際に表示されるはずです。

  1. IDEアイデアを再起動します
1
AlexPes

Windowsの場合、filles(jd2xsx.dll呼び出しとftd2xx.dll)をwindowws/system32フォルダーにロードすると、問題が解決することがわかりました。その後、新しいfd2xx.dllがパラメータに関係するという問題が発生したため、このdllの古いバージョンをロードする必要がありました。後でこれを書き直さなければなりません。

注:jd2xsx.dllはftd2xx.dllを呼び出すため、jd2xx.dllのパスを設定するだけでは機能しない場合があります。

0
Dan Carte

私は同じ問題を抱えていましたが、エラーはdllの名前変更が原因でした。ライブラリ名もdll内のどこかに書き込まれている可能性があります。元の名前に戻すと、System.loadLibraryを使用してロードできました

0

私はMac OS X YosemiteとNetbeans 8.02を使用していますが、同じエラーが発生しました。私が見つけた簡単な解決策は上記のようなものです。これはネイティブライブラリをプロジェクトに含める必要がある場合に便利です。 Netbeansの次の手順を実行します。

1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: Java -Djava.library.path="your_path"
5.- for example in my case: Java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok

誰かに役立つといいのですが。私が解決策を見つけたリンクはここにあります: Java.library.path –それは何で、どのように使用するか

0
Alex Ventura

WindowsのコマンドラインにJava -XshowSettings:propertiesと記述するだけで、Java.library.pathで示されるパスにすべてのファイルを貼り付けるだけです。

0
Ali Sasoli