java.lang.UnsatisfiedLinkError no *****. dll в java.library.path

92

Как я могу загрузить собственный файл DLL в свое веб-приложение? Я пробовал следующее:

  • Скопировал все необходимые dll в system32папку и попытался загрузить одну из них в ServletконструкторSystem.loadLibrary
  • Скопировал необходимые dll в tomcat_home/shared/libиtomcat_home/common/lib

Все эти dll есть в WEB-INF/libвеб-приложении.

Кетан Хайрнар
источник

Ответы:

156

Для 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

то он не может найти библиотеку foo (foo.dll) в вашем PATHили java.library.path. Если там написано что-то вроде:

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

тогда что-то не так с самой библиотекой в ​​том смысле, что Java не может сопоставить родную функцию Java в вашем приложении с ее фактическим родным аналогом.

Для начала я бы добавил немного времени в журнал вашего System.loadLibrary()звонка, чтобы увидеть, правильно ли он выполняется. Если он вызывает исключение или не находится в пути кода, который фактически выполняется, вы всегда будете получать последний тип, UnsatisfiedLinkErrorописанный выше.

Кстати, большинство людей помещают свои loadLibrary()вызовы в блок статического инициализатора в классе с собственными методами, чтобы гарантировать, что он всегда выполняется ровно один раз:

class Foo {

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

    public Foo() {
    }

}
Адам Баткин
источник
1
Поместив все dll в System32 и используя System.loadLibrary ("что-то") сработало. Я раньше делал System.loadLibrary ("something.dll"). Почему он не может загрузить все библиотеки из WEB-INF? Думаю, по умолчанию загружаются все банки. Что я могу сделать, чтобы загрузить эти dll из WEB-INF напрямую вместо System32 / указать их в java.library.path
Кетан Хайрнар,
2
+1 за «используйте« bla »вместо« bla.dll »в качестве loadLibrary()примечания - очень полезно, когда вы не знаете, что делаете не так.
MarnixKlooster ReinstateMonica
21
В моей системе (Linux и java7) мне нужен libпрефикс. Так System.loadLibrary("foo")нужно libfoo.so.
kristianlm
2
Спасибо. У меня это сработало, когда я обновил «PATH» для Windows, чтобы он содержал папку с файлом * .so.
user613114
Я мог бы поклясться, что требуется OSX blah.jnilibи Linux libblah.so. Итак, два часа спустя, после многочисленных попыток, я пришел к выводу, что OSX также требует libпрефикса
Йован Перович
15

Менять переменную java.library.path во время выполнения недостаточно, потому что она читается JVM только один раз. Вы должны сбросить его, например:

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 во время выполнения .

Александр
источник
10

Исходный ответ Адама Баткина приведет вас к решению, но если вы повторно развернете свое веб-приложение (без перезапуска веб-контейнера), вы должны столкнуться со следующей ошибкой:

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)

Это происходит потому, что ClassLoader, который изначально загрузил вашу DLL, по-прежнему ссылается на эту DLL. Однако ваше веб-приложение теперь работает с новым ClassLoader, и поскольку работает та же самая JVM, а JVM не допускает двух ссылок на одну и ту же DLL, вы не можете перезагрузить ее. Таким образом, ваше веб-приложение не может получить доступ к существующей DLL и не может загрузить новую. Итак .... вы застряли.

Документация Tomcat ClassLoader объясняет, почему ваше перезагруженное веб-приложение работает в новом изолированном ClassLoader и как можно обойти это ограничение (на очень высоком уровне).

Решение состоит в том, чтобы немного расширить решение Адама Баткина:

   package awesome;

   public class Foo {

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

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

    }

Затем поместите банку, содержащую ТОЛЬКО этот скомпилированный класс, в папку TOMCAT_HOME / lib.

Теперь в вашем веб-приложении вам просто нужно заставить Tomcat ссылаться на этот класс, что можно сделать так просто:

  Class.forName("awesome.Foo");

Теперь ваша DLL должна быть загружена в общий загрузчик классов, и на нее можно ссылаться из вашего веб-приложения даже после повторного развертывания.

Есть смысл?

Рабочую справочную копию можно найти в коде Google, static-dll-bootstrapper .

Мэтт М
источник
1
Этот ответ отлично подходит для серверов приложений, и у него должен быть отдельный вопрос, так как он теряется на этом вопросе.
JoshDM
8

Вы можете использовать, System.load()чтобы указать абсолютный путь, который вам нужен, а не файл в папке стандартной библиотеки для соответствующей ОС.

Если вам нужны уже существующие собственные приложения, используйте System.loadLibrary(String filename). Если вы хотите предоставить свой собственный, вам, вероятно, лучше использовать load ().

Вы также должны быть в состоянии использовать loadLibraryс java.library.pathнабором правильно. См. ClassLoader.javaИсточник реализации, показывающий оба проверяемых пути (OpenJDK)

Филип Уайтхаус
источник
Спасибо. Использование load на самом деле намного проще и интуитивно понятнее IMHO. Не могу заставить работать loadLibrary, что бы я ни делал ...
Планкалкюль
2
Это решение не работает для библиотек, которые загружают собственные собственные библиотеки.
Джастин Скилс
7

В случае, когда проблема заключается в том, что System.loadLibrary не может найти рассматриваемую DLL, одно распространенное заблуждение (подкрепленное сообщением об ошибке Java) заключается в том, что ответом является системное свойство java.library.path. Если вы установите системное свойство java.library.path на каталог, в котором находится ваша DLL, то System.loadLibrary действительно найдет вашу DLL. Однако, если ваша DLL, в свою очередь, зависит от других DLL, как это часто бывает, то java.library.path не может помочь, потому что загрузкой зависимых DLL полностью управляет операционная система, которая ничего не знает о java.library. путь. Таким образом, почти всегда лучше обойти java.library.path и просто добавить каталог вашей DLL в LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) или Path (Windows) до запуска JVM.

(Примечание: я использую термин «DLL» в общем смысле DLL или разделяемой библиотеки.)

Ян Эммонс
источник
5

Если вам нужно загрузить файл, относящийся к некоторому каталогу, в котором вы уже находитесь (например, в текущем каталоге), вот простое решение:

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());
Рик С. Ходжин
источник
4

Для тех, кто ищет java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path

Я столкнулся с тем же исключением; Я перепробовал все, и важные вещи, чтобы заставить его работать:

  1. Правильная версия pdf lib.jar (в моем случае это была неправильная версия jar, хранящаяся во время выполнения сервера)
  2. Создайте папку и сохраните в ней jar pdflib и добавьте папку в свою переменную PATH

Он работал с tomcat 6.

Мангеш М. Кулкарни
источник
3
  1. Если вы считаете, что добавили путь к собственной библиотеке %PATH%, попробуйте выполнить тестирование с помощью:

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

Он должен показать вам, действительно ли ваша DLL включена %PATH%

  1. Перезапустите IDE Idea, которая, похоже, сработала для меня после того, как я установил переменную env, добавив ее в %PATH%
AlexPes
источник
2

Бедный я! потратил на это целый день. Пишу здесь, если кто-то повторяет эту проблему.

Я пытался загрузить, как предлагал Адам, но затем попался с исключением AMD64 vs IA 32. Если в любом случае после работы в соответствии с пошаговым руководством Адама (без сомнения, лучший выбор), попробуйте установить 64-разрядную версию последней jre. ваши JRE и JDK являются 64-битными, и вы правильно добавили его в свой путь к классам.

Вот мой рабочий пример: неудовлетворенная ошибка ссылки

Sayannayas
источник
0

Для Windows я обнаружил, что когда я загружал файлы (вызовы jd2xsx.dll и ftd2xx.dll) в папку windowws / system32, это решало проблемы. Затем у меня возникла проблема с моей новой fd2xx.dll, связанной с параметрами, поэтому мне пришлось загрузить старую версию этой dll. Мне придется это вынести позже.

Примечание: jd2xsx.dll вызывает ftd2xx.dll, поэтому установка пути для jd2xx.dll может не сработать.

Дэн Карт
источник
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 - что это такое и как использовать

Alexventuraio
источник
Привет, Алекс, у меня есть вопрос, есть ли проблема, если путь к библиотеке включает в себя некоторый интервал в пути в этой строкеVM Options: java -Djava.library.path="your_path"
Локеш Пандей
Ммм, я не работаю с Java в течение последнего года, но, поскольку могут возникнуть конфликты, я рекомендую избегать добавления пустых пробелов в путь к файлу .
alexventuraio
0

У меня была такая же проблема, и ошибка была связана с переименованием библиотеки DLL. Может случиться так, что имя библиотеки также написано где-то внутри dll. Когда я вернул его исходное имя, я смог загрузить, используяSystem.loadLibrary

Алессандро Марини
источник
0

Это просто, просто напишите java -XshowSettings: properties в командной строке в Windows, а затем вставьте все файлы в путь, указанный в java.library.path.

Али Сасоли
источник
0

Во-первых, вам нужно убедиться, что каталог вашей собственной библиотеки находится в каталоге java.library.path. Посмотрите, как это сделать здесь . Затем вы можете позвонить System.loadLibrary(nativeLibraryNameWithoutExtension)- убедитесь, что расширение файла не включено в имя вашей библиотеки.

Регион39
источник