Як виправити UnsatisfiedLinkError (не вдається знайти залежні бібліотеки) у проекті JNI


85

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

Коли я запускаю свою програму, вона аварійно завершує роботу

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

Я шукав цей сайт (та інші) і спробував ряд виправлень:

  1. Я побіг на ходунців. DW дав кілька попереджень - що дві бібліотеки, необхідні для libsndfile, MPR.DLL та SHLWAPI.DLL, мали "невирішені імпорти", але відповіді на поширені запитання про DW говорили, що ці попередження можна безпечно ігнорувати.

  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. Тому я не думаю, що проблема в тому, що вони не на шляху. Але все одно дякую.
дБ,

7
У Windows нам довелося помістити .dll-файли в каталог [JRE] \ bin (те саме місце, де знаходиться java.exe тощо), щоб Java бачила їх автоматично, не маючи на увазі параметри командного рядка або змінні середовища.
QuantumMechanic

4
Хм ... добре, я спробував помістити всі свої .dll у [JRE] \ bin. Це працює!
дБ,

Відповіді:


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. Зараз все це має більше сенсу.
дБ,

Будь ласка, можете пояснити, як ви подолали цю проблему?
SL_User

5
@SL_User Я думаю, якщо ви додасте каталог, де знаходяться бібліотеки, до змінної середовища "path" і перезапустите командний рядок або термінал, він повинен це виправити. Java шукає банки під classpath, а бібліотеки під path.
xxjjnn

1
На підставі цієї відповіді, схоже , що команда для поновлення 2 доступний з принаймні Java 7: stackoverflow.com/a/8472139/901641
ArtOfWarfare

18

Я хочу повідомити про цей цікавий випадок, після того як спробував усі вищезазначені методи, помилка все ще є. Дивна річ - це працює на комп’ютері з Windows 7, а на Windows XP - ні. Потім я використовую програму залежностей і виявив, що у Windows XP немає VC ++ Runtime як моєї вимоги до DLL. Після встановлення пакету VC ++ Runtime тут він працює як шарм. Мене непокоїло те, що він продовжує говорити. Не вдається знайти залежні бібліотеки, тоді як інтуїтивно існує DLL, який залежить, проте, нарешті, виявляється, що JNL, який залежить від DLI, потребує іншого залежного dl. Сподіваюся, це допоможе.


4
Повідомлення є правильним, хоча в цьому випадку вводить в оману. У мене відсутні як середовища виконання VC ++ у тестовому полі, так і бібліотека, скомпільована в режимі налагодження (залежно від часу розповсюдження, що не підлягає розповсюдженню). Залежність Уокера дуже допомогла розібратися в цьому.
Johnny Baloney

виникла та сама проблема з використанням jnetpcap-library. winpcap залежності більше не встановлювався на машині, а повідомлення про виняток вводило в оману
BlackFlag

я думаю, що це може бути мій випадок.
І.Тайгер

У наші дні людина, яка страждає на залежність, стає досить «довгою в зубі». Він не зміг відкрити нещодавно встановлену Windows 10/64-бітну DLL, тому я все ще не знаю, якої бібліотеки не вистачає ... Вій.
Mark Storer


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 / рідна межа): jvm використовує "java.library.path" (який за замовчуванням $ PATH) для пошуку dll
    3. чистий рідний світ: рідний код використовує $ PATH для завантаження інших dll

2

Я знайшов чудову статтю деяких друзів із пам’ятки, яка пережила те саме, що і я. Це спрацювало для мене, тому, сподіваюся, це допоможе і вам! Почитайте, якщо вам цікаво ( Небезпека завантаження власних бібліотек на 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, і він працює зараз. Я зробив щось на зразок:

ВСТАНОВИТИ ШЛЯХ = "/ 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. У повідомленні про помилку вказувалося, що не вдалося знайти dll-файл db2jcct2, або не вдалося знайти залежні бібліотеки для цього 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.