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"). Чому він не може завантажувати всі DLL з WEB-INF? Я думаю, це завантажує всі банки за замовчуванням. Що я можу зробити, щоб завантажити ці dll з WEB-INF безпосередньо замість System32 / вказати їх у java.library.path
Ketan Khairnar,

2
+1 для "використовуйте" bla "замість" bla.dll "для loadLibrary()зауваження - дуже корисно, коли ви не уявляєте, що робите неправильно.
MarnixKlooster ReinstateMonica

21
У моїй системі (Linux і java7) мені потрібен libпрефікс. Тож System.loadLibrary("foo")потреби libfoo.so.
kristianlm

2
Дякую. Це спрацювало для мене, коли я оновив "ШЛЯХ" для Windows, так що він містить папку з файлом * .so.
user613114

Я міг би поклястись, що OSX потрібен blah.jnilibі Linux libblah.so. Ну, через дві години, після численних спроб, я дійшов висновку, що OSX також вимагає libпрефікса
Jovan Perovic

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 не дозволяє 2 посилання на одну і ту ж DLL, ви не можете перезавантажити його. Таким чином, ваш веб-додаток не може отримати доступ до існуючої DLL і не може завантажити нову. Отже .... ти застряг.

Документація Tomcat's 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) {
        }

    }

Потім помістіть банку, що містить JUST цей скомпільований клас, у папку TOMCAT_HOME / lib.

Тепер у вашому веб-додатку вам просто потрібно змусити Tomcat посилатися на цей клас, що можна зробити так просто, як це:

  Class.forName("awesome.Foo");

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

Мати сенс?

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


1
Ця відповідь чудова для серверів додатків і повинна мати своє власне запитання, оскільки вона марно витрачається на це питання.
JoshDM

8

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

Якщо ви хочете власні програми, які вже існують, використовуйте System.loadLibrary(String filename). Якщо ви хочете надати своє, вам, мабуть, краще завантажити ().

Ви також повинні мати можливість правильно використовувати loadLibraryз java.library.pathнабором. Див. ClassLoader.javaДжерело реалізації, що показує обидва перевіряються шляхи (OpenJDK)


Дякую. Використовувати навантаження насправді набагато простіше та інтуїтивніше IMHO. Не вдалося отримати loadLibrary для роботи незалежно від того, що я робив ...
Plankalkül

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. Створіть папку, збережіть у ній банку pdflib та додайте папку до змінної PATH

Це працювало з tomcat 6.


3
  1. Якщо ви вважаєте, що додали шлях до рідної бібліотеки %PATH%, спробуйте протестувати за допомогою:

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

Він повинен показати вам насправді, якщо ваш dll увімкнено %PATH%

  1. Перезапустіть IDE Idea, який, здавалося, працював у мене після того, як я налаштував змінну env, додавши її до %PATH%

2

Бідний я ! провів за цим цілий день. Пишучи тут, якщо хтось повторює цю проблему.

Я намагався завантажити, як запропонував Адам, але потім потрапив на виняток AMD64 проти IA 32. Якщо в будь-якому випадку після роботи відповідно до покрокового керівництва Адама (без сумніву, найкращого вибору), спробуйте встановити 64-бітну версію останнього jre. ваш JRE та JDK є 64-бітними, і ви правильно додали його до шляху до вашого класу.

Мій робочий приклад йде тут: нестатифікована помилка посилання


0

Для Windows я виявив, що коли я завантажував файли (jd2xsx.dll викликає & ftd2xx.dll) у папку windowsws / 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 - що це таке і як використовувати


Привіт Алекс, у мене питання, чи є якісь проблеми, якщо шлях до бібліотеки включає певний інтервал у шляху в цьому рядкуVM Options: java -Djava.library.path="your_path"
Lokesh Pandey

Ммм. Я не працюю з Java останній рік, але оскільки можуть виникати конфлікти, рекомендую уникати додавання порожніх пробілів у шляху до файлу .
alexventuraio

0

У мене була та ж проблема, і помилка сталася через перейменування dll. Може трапитися так, що назва бібліотеки також написана десь усередині dll. Коли я повернув його початкову назву, я зміг завантажити за допомогоюSystem.loadLibrary


0

Просто напишіть java -XshowSettings: Properties у вашому командному рядку у вікнах, а потім вставте всі файли у шлях, показаний java.library.path.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.