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


92

Jak mogę załadować niestandardowy plik dll w mojej aplikacji internetowej? Wypróbowałem następujące:

  • Skopiowałem wszystkie wymagane biblioteki dll w system32folderze i próbowałem załadować jeden z nich w ServletkonstruktorzeSystem.loadLibrary
  • Skopiowano wymagane biblioteki DLL do tomcat_home/shared/libitomcat_home/common/lib

Wszystkie te biblioteki DLL znajdują się w WEB-INF/libaplikacji internetowej

Odpowiedzi:


156

Aby System.loadLibrary()biblioteka (w systemie Windows, DLL) działała, musi znajdować się w katalogu gdzieś na twoim komputerze PATH lub na ścieżce wymienionej we java.library.pathwłaściwości systemowej (abyś mógł uruchomić Javę java -Djava.library.path=/path/to/dir).

Dodatkowo w przypadku loadLibrary()określasz nazwę podstawową biblioteki, bez .dllkońcówki. Więc po /path/to/something.dllprostu używałbyś System.loadLibrary("something").

Musisz także dokładnie przyjrzeć się temu UnsatisfiedLinkError, co otrzymujesz. Jeśli mówi coś takiego:

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

wtedy nie może znaleźć biblioteki foo (foo.dll) w twoim PATHlub java.library.path. Jeśli mówi coś takiego:

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

wtedy coś jest nie tak z samą biblioteką w tym sensie, że Java nie jest w stanie odwzorować natywnej funkcji Java w twojej aplikacji na jej rzeczywisty natywny odpowiednik.

Na początek umieściłbym trochę rejestrowania twojego System.loadLibrary()wywołania, aby sprawdzić, czy działa poprawnie. Jeśli zgłosi wyjątek lub nie znajduje się w ścieżce kodu, która jest faktycznie wykonywana, zawsze otrzymasz ten drugi typ UnsatisfiedLinkErrorwyjaśniony powyżej.

Na marginesie, większość ludzi umieszcza swoje loadLibrary()wywołania w statycznym bloku inicjalizatora w klasie z metodami natywnymi, aby upewnić się, że jest on wykonywany zawsze dokładnie raz:

class Foo {

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

    public Foo() {
    }

}

1
Umieszczenie wszystkich bibliotek dll w System32 i użycie System.loadLibrary („coś”) zadziałało. Robiłem wcześniej System.loadLibrary („coś.dll”). Dlaczego nie można załadować wszystkich bibliotek dll z WEB-INF? Domyślam się, że domyślnie ładuje wszystkie słoiki. Co mogę zrobić, aby załadować te biblioteki DLL z WEB-INF bezpośrednio zamiast z System32 / określić je w java.library.path
— Ketan Khairnar

2
+1 za „użyj„ bla ”zamiast„ bla.dll ”jako loadLibrary()uwagi - bardzo przydatne, gdy nie masz pojęcia, co robisz źle.
— MarnixKlooster ReinstateMonica

21
W moim systemie (Linux i java7) potrzebuję libprefiksu. Więc System.loadLibrary("foo")potrzebuje libfoo.so.
— kristianlm

2
Dzięki. U mnie zadziałało, kiedy zaktualizowałem „PATH” dla systemu Windows, tak że zawiera folder zawierający plik * .so.
— user613114

Mógłbym przysiąc, że wymagany jest OSX blah.jnilibi Linux libblah.so. Cóż, dwie godziny później, po wielu próbach, doszedłem do wniosku, że OSX również wymaga libprefiksu
— Jovan Perovic

15

Zmiana zmiennej „java.library.path” w czasie wykonywania nie wystarczy, ponieważ jest ona odczytywana tylko raz przez maszynę JVM. Musisz to zresetować jak:

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);

Zdobądź łup w: Changing Java Library Path at Runtime .


10

Oryginalna odpowiedź Adama Batkina doprowadzi Cię do rozwiązania, ale jeśli ponownie wdrożysz aplikację internetową (bez ponownego uruchamiania kontenera internetowego), powinieneś napotkać następujący błąd:

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)

Dzieje się tak, ponieważ ClassLoader, który pierwotnie załadował bibliotekę DLL, nadal odwołuje się do tej biblioteki DLL. Jednak Twoja aplikacja internetowa działa teraz z nowym ClassLoaderem, a ponieważ ta sama JVM jest uruchomiona, a JVM nie zezwala na 2 odwołania do tej samej biblioteki DLL, nie możesz jej ponownie załadować . Dlatego Twoja aplikacja internetowa nie może uzyskać dostępu do istniejącej biblioteki DLL i nie może załadować nowej. Więc ... utknęłaś.

Dokumentacja Tomcat ClassLoader przedstawia, dlaczego ponownie załadowana aplikacja internetowa działa w nowej, izolowanej aplikacji ClassLoader i jak można obejść to ograniczenie (na bardzo wysokim poziomie).

Rozwiązaniem jest niewielkie rozszerzenie rozwiązania Adama Batkina:

   package awesome;

   public class Foo {

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

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

    }

Następnie umieść jar zawierający TYLKO tę skompilowaną klasę w folderze TOMCAT_HOME / lib.

Teraz w aplikacji internetowej wystarczy zmusić Tomcat do odwoływania się do tej klasy, co można zrobić tak prosto:

  Class.forName("awesome.Foo");

Teraz Twoja biblioteka DLL powinna zostać załadowana do wspólnego modułu ładującego klasy i można do niej odwoływać się z aplikacji internetowej nawet po ponownym wdrożeniu.

Ma sens?

Roboczą kopię referencyjną można znaleźć w google code, static-dll-bootstrapper .


1
Ta odpowiedź jest doskonała dla serwerów aplikacji i powinna mieć własne pytanie, ponieważ jest marnowana na to pytanie.
— JoshDM

8

Możesz użyć, System.load()aby podać bezwzględną ścieżkę, która jest tym, czego chcesz, zamiast pliku w folderze biblioteki standardowej dla odpowiedniego systemu operacyjnego.

Jeśli potrzebujesz natywnych aplikacji, które już istnieją, użyj System.loadLibrary(String filename). Jeśli chcesz udostępnić własne, prawdopodobnie lepiej będzie z load ().

Powinieneś także umieć poprawnie korzystać loadLibraryz java.library.pathzestawu. Zobacz ClassLoader.javaźródło implementacji pokazujące obie sprawdzane ścieżki (OpenJDK)


Dzięki. Korzystanie z obciążenia jest w rzeczywistości znacznie łatwiejsze i bardziej intuicyjne w IMHO. Nie można uruchomić loadLibrary bez względu na to, co zrobiłem ...
— Plankalkül

2
To rozwiązanie nie działa w przypadku bibliotek, które ładują własne biblioteki natywne.
— Justin Skiles

7

W przypadku, gdy problem polega na tym, że System.loadLibrary nie może znaleźć danej biblioteki DLL, jednym z powszechnych nieporozumień (potwierdzonych komunikatem o błędzie języka Java) jest to, że odpowiedzią jest właściwość systemowa java.library.path. Jeśli ustawisz właściwość systemową java.library.path na katalog, w którym znajduje się biblioteka DLL, wówczas System.loadLibrary rzeczywiście znajdzie tę bibliotekę DLL. Jeśli jednak biblioteka DLL jest z kolei zależna od innych bibliotek DLL, co często się zdarza, java.library.path nie może pomóc, ponieważ ładowaniem zależnych bibliotek DLL zarządza w całości system operacyjny, który nic nie wie o java.library. ścieżka. Dlatego prawie zawsze lepiej jest ominąć java.library.path i po prostu dodać katalog biblioteki DLL do LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) lub Path (Windows) przed uruchomieniem JVM.

(Uwaga: używam terminu „DLL” w ogólnym znaczeniu biblioteki DLL lub biblioteki współdzielonej).


5

Jeśli chcesz załadować plik, który jest powiązany z katalogiem, w którym już jesteś (np. W bieżącym katalogu), oto proste rozwiązanie:

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

Dla szukających java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path

Miałem ten sam wyjątek; Próbowałem wszystkiego, a ważne rzeczy, aby to działało, to:

  1. Poprawna wersja pliku pdf lib.jar (w moim przypadku był to zły jar wersji przechowywany w środowisku wykonawczym serwera)
  2. Utwórz folder i zachowaj w nim jar pdflib i dodaj ten folder do zmiennej PATH

To działało z tomcat 6.


3
  1. Jeśli uważasz, że dodałeś ścieżkę natywnej biblioteki do %PATH%, spróbuj przetestować z:

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

Powinien pokazać ci, czy twoja dll jest włączona %PATH%

  1. Zrestartuj pomysł IDE, który wydawał się działać po skonfigurowaniu zmiennej env, dodając ją do pliku %PATH%

2

Biedny ja ! spędził za tym cały dzień, zapisując to tutaj, jeśli ktoś powiela ten problem.

Próbowałem załadować, jak zasugerował Adam, ale potem złapałem wyjątek AMD64 vs IA 32.Jeśli w jakimkolwiek przypadku po pracy zgodnie z instrukcją Adama (bez wątpienia najlepszym wyborem), spróbuj mieć 64-bitową wersję najnowszego jre. twoje JRE i JDK są 64-bitowe i poprawnie dodałeś je do swojej ścieżki klas.

Oto mój przykład roboczy: błąd niezadowolonego linku


0

W przypadku systemu Windows stwierdziłem, że po załadowaniu plików filles (wywołania jd2xsx.dll & ftd2xx.dll) do folderu windowws / system32 rozwiązało to problemy. Wtedy miałem problem z moim nowszym fd2xx.dll związanym z parametrami, dlatego musiałem załadować starszą wersję tej biblioteki dll. Będę musiał to później przerobić.

Uwaga: jd2xsx.dll wywołuje ftd2xx.dll, więc samo ustawienie ścieżki do jd2xx.dll może nie działać.


0

Używam Mac OS X Yosemite i Netbeans 8.02, mam ten sam błąd, a proste rozwiązanie, które znalazłem, jest takie jak powyżej, jest to przydatne, gdy potrzebujesz włączyć natywną bibliotekę do projektu. Zrób więc następną dla 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

Mam nadzieję, że komuś się przyda. Link gdzie znalazłem rozwiązanie jest tutaj: java.library.path - co to jest i jak z niego korzystać


Cześć Alex, mam pytanie, czy jest jakiś problem, jeśli ścieżka biblioteki zawiera odstępy w ścieżce w tej liniiVM Options: java -Djava.library.path="your_path"
— Lokesh Pandey,

Mmm Nie pracuję z Javą przez ostatni rok, ale ponieważ mogą pojawić się konflikty, radzę unikać dodawania pustych spacji w ścieżce pliku .
— alexventuraio,

0

Miałem ten sam problem i błąd był spowodowany zmianą nazwy dll. Może się zdarzyć, że nazwa biblioteki jest również zapisana gdzieś w dll. Kiedy przywróciłem jego pierwotną nazwę, mogłem załadować za pomocąSystem.loadLibrary


0

To proste, wystarczy napisać java -XshowSettings: properties w wierszu poleceń w systemie Windows, a następnie wkleić wszystkie pliki w ścieżce pokazanej przez java.library.path.


0

Najpierw upewnij się, że katalog Twojej biblioteki natywnej znajduje się w katalogu java.library.path. Zobacz, jak to zrobić tutaj . Następnie możesz zadzwonić System.loadLibrary(nativeLibraryNameWithoutExtension)- uważając, aby nie dodawać rozszerzenia pliku w nazwie biblioteki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.