Как исправить ошибку UnsatisfiedLinkError (не удается найти зависимые библиотеки) в проекте JNI


86

Я работаю над проектом Java, который использует JNI. JNI вызывает пользовательскую библиотеку, которую я написал сам, скажем, mylib.dll, которая зависит от сторонней библиотеки libsndfile-1.dll.

Когда я запускаю свою программу, она вылетает с

java.lang.UnsatisfiedLinkError:  C:\...path...\mylib.dll: Can't find dependent libraries.

Я искал этот сайт (и другие) и попробовал несколько исправлений:

  1. Я запустил dependency walker. DW выдал пару предупреждений - что две библиотеки, требуемые libsndfile, MPR.DLL и SHLWAPI.DLL, имеют «неразрешенный импорт», но в DW FAQ сказано, что эти предупреждения можно безопасно игнорировать.

  2. Я исправил имена методов в mylib.dll, как было предложено здесь . Имена методов каким-то образом были искажены компилятором, но я добавил флаги компоновщика, и теперь имена методов dll в точности совпадают с именами в моем заголовочном файле jni.

  3. Я помещаю все эти DLL в один и тот же каталог - в тот же каталог, что и вызывающий их .jar - чтобы убедиться, что они находятся в правильном ПУТИ.

Никаких кубиков.

Кто-нибудь знает, что происходит?

Я занимаюсь разработкой в ​​Visual Studio 2010 на MacBook Pro (через Parallels). Тестирую в Windows XP на ноутбуке toshiba.


1
вы установили -Djava.library.path?
Йохен Бедерсдорфер

На самом деле нет, потому что я не запускаю программу из командной строки. Я пишу библиотеку для Processing (processing.org), и Processing отвечает за запуск моего кода. Однако я проверил путь к библиотеке java во время выполнения, и папка, содержащая мои библиотеки DLL, находится на нем.
дБ '23

Как я уже сказал, все библиотеки DLL находятся в одной папке, рядом с моим файлом .jar. Поэтому я не думаю, что проблема в том, что они не на пути. Но все равно спасибо.
дБ '23

7
В Windows нам приходилось помещать файлы .dll в каталог [JRE] \ bin (то же место, где находится java.exe и т. Д.), Чтобы Java могла видеть их автоматически, не прибегая к параметрам командной строки или переменным среды.
QuantumMechanic

4
Хм ... хорошо, я попытался поместить все свои .dll в [JRE] \ bin. Это работает!
дБ '23

Ответы:


52

Я почти уверен, что путь к классам и путь поиска разделяемой библиотеки мало связаны друг с другом. Согласно книге JNI (которая, по общему признанию, устарела), в Windows, если вы не используете java.library.pathсистемное свойство, DLL должна находиться в текущем рабочем каталоге или в каталоге, указанном в PATHпеременной среды Windows .


Обновить:

Похоже, Oracle удалила PDF-файл со своего веб-сайта. Я обновил ссылку выше, чтобы указать на экземпляр PDF-файла из Техасского университета в Арлингтоне.

Также вы можете прочитать HTML-версию спецификации JNI от Oracle . Он находится в разделе Java 8 на веб-сайте Java и, надеюсь, будет там какое-то время.


Обновление 2:

По крайней мере, в Java 8 (я не проверял более ранние версии) вы можете:

java -XshowSettings:properties -version

чтобы найти путь поиска в общей библиотеке. Найдите значение java.library.pathсвойства в этих выходных данных.


2
Ага, CLASSPATHсовсем не используется. Я тоже не уверен, что он cwdвообще используется. java.library.pathили просто PATHбудет работать. @dB ', то место, где вы их сейчас разместили, неправильное .
Эрнест Фридман-Хилл

Большое спасибо, ребята! Я думаю, что часть проблемы здесь заключалась в путанице с моей стороны между переменной среды Windows PATH, java.library.path и java CLASSPATH. Теперь все обретает смысл.
дБ '23

Не могли бы вы объяснить, как вы преодолели эту проблему?
SL_User

5
@SL_User Я думаю, что если вы добавите каталог, в котором находятся библиотеки, в переменную окружения «path» и перезапустите командную строку или терминал, он должен это исправить. Java ищет jar-файлы по пути к классам и библиотеки по пути.
xxjjnn 02

1
Основываясь на этом ответе, похоже, что эта команда для обновления 2 была доступна по крайней мере с Java 7: stackoverflow.com/a/8472139/901641
ArtOfWarfare

18

Я хочу сообщить об этом интересном случае, после того, как попробовал все вышеперечисленные методы, ошибка все еще существует. Странно то, что он работает на компьютере с Windows 7, а на Windows XP - нет. Затем я использую обходчик зависимостей и обнаружил, что в Windows XP нет VC ++ Runtime как моего требования к dll. После установки пакета VC ++ Runtime здесь он работает как шарм. Что меня беспокоило, так это то, что он продолжает говорить: «Не могу найти зависимые библиотеки», хотя интуитивно зависимая dll от JNI присутствует, однако, наконец, оказывается, что для зависимой от JNI dll требуется другая зависимая dl. Надеюсь, это поможет.


4
Сообщение верное, хотя и вводящее в заблуждение в данном случае. В тестовом блоке отсутствовали как среда выполнения VC ++, так и библиотека, скомпилированная в режиме отладки (в зависимости от среды выполнения отладки, не распространяемой повторно). Dependency Walker очень помог разобраться в этом.
Джонни Балони

была такая же проблема с использованием jnetpcap-библиотеки. зависимость winpcap больше не была установлена ​​на машине, и сообщение об исключении
вводило в

Я думаю, это может быть мой случай.
I.Tyger

В наши дни ходунки на иждивении становятся довольно «длинными в зубах». Он вообще не мог открыть последнюю версию Windows 10/64-bit dll, поэтому я до сих пор не знаю, какая библиотека отсутствует ...
Марк Сторер


5

Убедитесь, что путь к вашей библиотеке правильный или нет. Конечно, вы можете использовать следующий код, чтобы проверить путь к вашей библиотеке: System.out.println(System.getProperty("java.library.path"));

Вы можете указать путь java.library.path при запуске приложения Java:

java -Djava.library.path=path ...

4

Если вы загружаете 32-битную версию своей DLL с 64-битной JRE, у вас может быть эта проблема. Это был мой случай.


Скорее всего, это тоже мой случай; если кто-то знает об известных обходных путях, мне было бы интересно; за исключением загрузки 64-битной версии, поскольку в данном случае это не dll, а chromedriver.exeдрайвер Selenium для Chrome, который, насколько я могу судить, поставляется только в 32-битной версии.
SantiBailors

4

Была такая же проблема с машиной XP при установке javacvи opencvв сочетании с Eclipse. Оказалось, что мне не хватало следующих файлов:

  • msvcp100.dll
  • msvcr100.dll

После их установки проект компилировался и работал нормально.


У меня аналогичная проблема, которая исчезает после установки «Распространяемого пакета Microsoft Visual C ++ 2010 SP1 (x86)»
Кирилл Михайлов

2
  • Краткий ответ: в случае ошибки "не удается найти зависимую библиотеку" проверьте свой $ PATH (соответствует пункту 3 ниже)
  • Длинный ответ:
    1. Чистый мир java: jvm использует «путь к классам» для поиска файлов классов
    2. Мир JNI (граница java / native): jvm использует "java.library.path" (по умолчанию $ PATH) для поиска dll.
    3. чистый собственный мир: собственный код использует $ PATH для загрузки других dll

2

Я нашел отличную статью некоторых друзей в keepafe, в которой повторилось то же самое, что и я. У меня это сработало, так что, надеюсь, это поможет и вам! Прочтите, если вам интересно ( Опасности загрузки собственных библиотек на Android ), или просто используйте

compile 'com.getkeepsafe.relinker:relinker:1.2.3'

и заменить

System.loadLibrary("myLibrary");

с участием

ReLinker.loadLibrary(context, "mylibrary");

1

Раньше у меня была точно такая же проблема, и наконец ее решили.

Я поместил все зависимые библиотеки DLL в ту же папку, где хранился mylib.dll, и убедился, что компилятор JAVA может найти его (если в пути компиляции нет mylib.dll, во время компиляции будет сообщение об ошибке). Важно отметить, что вы должны убедиться, что все зависимые библиотеки имеют одну и ту же версию с mylib.dll, например, если ваш mylib.dll является версией выпуска, вы также должны поместить туда версию выпуска всех зависимых библиотек. .

Надеюсь, это поможет другим, кто столкнулся с той же проблемой.


1

У меня была такая же проблема, и я попробовал все, что написано здесь, чтобы исправить это, но у меня ничего не сработало. В моем случае я использую Cygwin для компиляции dll. Кажется, что JVM пытается найти библиотеки DLL JRE в виртуальном пути Cygwin. Я добавил путь виртуального каталога Cygwin к библиотекам DLL JRE, и теперь он работает. Я сделал что-то вроде:

SET PATH = "/ cygdrive / c / Program Files / Java / jdk1.8.0_45";% PATH%


1

В моей ситуации я пытался запустить веб-службу java в Tomcat 7 через коннектор в Eclipse. Приложение работало нормально, когда я развернул файл войны на экземпляре Tomcat 7 на моем ноутбуке. Приложению требуется драйвер jdbc типа 2 для «IBM DB2 9.5». По какой-то странной причине коннектор в Eclispe не мог видеть или использовать пути в переменных среды IBM DB2 для доступа к файлам dll, установленным на моем ноутбуке в качестве клиента jcc. В сообщении об ошибке либо говорилось, что не удалось найти файл db2jcct2 dll, либо не удалось найти зависимые библиотеки для этого файла dll. В конце концов, я удалил соединитель и восстановил его. Тогда все заработало нормально. Я добавляю это решение в качестве документации, потому что мне не удалось найти это конкретное решение где-либо еще.


0

У меня сработало создание статической библиотеки, компиляция с использованием g++ -static. Он связывает зависимые библиотеки вместе со сборкой.



0

поместите необходимые dll в папку и установите путь к папке в переменной среды PATH. убедитесь, что отражена обновленная переменная PATH среды.


0

Я столкнулся с той же проблемой с библиотекой ffmpeg после объединения двух проектов Android в один проект.

На самом деле проблема возникла из-за двух разных версий библиотеки ffmpeg, но они были загружены в память с одинаковыми именами. Одна библиотека была помещена в JNiLibs, а другая - внутри другой библиотеки, используемой в качестве модуля. Мне не удалось изменить код модуля, поскольку он был доступен только для чтения, поэтому я переименовал тот, который использовался в моем собственном коде, в ffmpegCamera и загрузил его в память с тем же именем.

System.loadLibrary("ffmpegCamera");

Это устранило проблему, и теперь обе версии библиотек загружаются в память с отдельным именем и идентификатором процесса.


0

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

Поскольку операционная система не имеет понятия об этом java.library.path, она не увидит никаких каталогов, которые вы разместите в java.library.path. Вместо этого он будет искать только каталоги в переменной среды PATH операционной системы. Это совершенно нормально, если зависимость собственной библиотеки является собственной библиотекой операционной системы, потому что она будет найдена в PATH. Однако, если зависимость собственной библиотеки является собственной библиотекой, созданной вами или кем-то еще, она не будет найдена в PATH, если вы не поместите ее туда. Такое поведение является странным, неожиданным и плохо документированным, но оно задокументировано в системе отслеживания проблем OpenJDK здесь . Вы также можете найти еще один ответ StackOverflow, подкрепляющий это объяснение, здесь .

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


-2
  1. Перейдите на http://tess4j.sourceforge.net/usage.html и нажмитеVisual C++ Redistributable for VS2012
  2. Загрузите его и запустите VSU_4\vcredist_x64.exeили в VSU_4\vcredist_x84.exeзависимости от конфигурации вашей системы
  3. Поместите свои dllфайлы в libпапку вместе с другими библиотеками (например \lib\win32-x86\your dll files).
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.