web-dev-qa-db-fra.com

java.lang.UnsatisfiedLinkError no *****. dll dans Java.library.path

Comment puis-je charger un fichier dll personnalisé dans mon application Web? J'ai essayé de suivre les moyens mais son échec.

  • copié toutes les dll requises dans le dossier system32 et essayé de charger l’une d’elles dans le constructeur ServletSystem.loadLibrary
  • Dll requis copiées dans Tomcat_home/shared/lib et Tomcat_home/common/lib
  • toutes ces dll sont dans WEB-INF/lib de l'application web
83
Ketan Khairnar

Pour que System.loadLibrary() fonctionne, la bibliothèque (sous Windows, une DLL) doit figurer dans un répertoire situé quelque part sur votre PATH ou sur un chemin répertorié dans la propriété système Java.library.path (afin que vous puissiez lancer Java comme Java -Djava.library.path=/path/to/dir).

De plus, pour loadLibrary(), vous spécifiez le nom de base de la bibliothèque, sans le .dll à la fin. Donc, pour /path/to/something.dll, vous utiliseriez simplement System.loadLibrary("something").

Vous devez également regarder la UnsatisfiedLinkError exacte que vous obtenez. Si cela dit quelque chose comme:

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

alors il ne peut pas trouver le foo bibliothèque (foo.dll) dans votre PATH ou Java.library.path. Si cela dit quelque chose comme:

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

alors, quelque chose ne va pas avec la bibliothèque elle-même, en ce sens que Java ne peut pas mapper une fonction Java native dans votre application à sa contrepartie native.

Pour commencer, je mettrais un peu de journalisation autour de votre appel System.loadLibrary() pour voir si cela s’exécute correctement. S'il lève une exception ou s'il ne se trouve pas dans un chemin de code réellement exécuté, vous obtiendrez toujours le dernier type de UnsatisfiedLinkError expliqué ci-dessus.

En tant que note de bas de page, la plupart des gens placent leurs appels loadLibrary() dans un bloc d'initialiseur statique dans la classe avec les méthodes natives, pour s'assurer qu'il est toujours exécuté exactement une fois:

class Foo {

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

    public Foo() {
    }

}
140
Adam Batkin

Changer la variable 'Java.library.path' au moment de l'exécution n'est pas suffisant car elle est lue une seule fois par la JVM. Vous devez le réinitialiser comme ceci:

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

S'il vous plaît, prenez un butin sur: Modification du chemin de la bibliothèque Java à l'exécution .

11
Alexandre

La réponse originale d'Adam Batkin vous mènera à une solution, mais si vous redéployez votre application Web (sans redémarrer votre conteneur Web), vous devriez rencontrer l'erreur suivante:

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)

Cela est dû au fait que le chargeur de classe qui a initialement chargé votre DLL fait toujours référence à cette DLL. Cependant, votre application Web fonctionne maintenant avec un nouveau ClassLoader et, comme la même machine virtuelle est en cours d'exécution et qu'une machine virtuelle n'autorisera pas 2 références à la même DLL, vous ne pouvez pas le recharger. Ainsi, votre application Web ne peut pas accéder à la DLL existante ni en charger une nouvelle. Alors .... vous êtes coincé. 

La documentation ClassLoader de Tomcat explique pourquoi votre application Web rechargée s'exécute dans un nouveau ClassLoader isolé et comment vous pouvez contourner cette limitation (à un niveau très élevé).

La solution consiste à étendre un peu la solution d'Adam Batkin:

   package awesome;

   public class Foo {

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

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

    }

Ensuite, placez un fichier JAR contenant JUST cette classe compilée dans le dossier Tomcat_HOME/lib.

Maintenant, dans votre application Web, vous devez simplement forcer Tomcat à faire référence à cette classe, ce qui peut se faire aussi simplement que:

  Class.forName("awesome.Foo");

Maintenant, votre DLL doit être chargée dans le chargeur de classe commun et peut être référencée à partir de votre application Web, même après avoir été redéployée.

Avoir un sens?

Une copie de référence de travail peut être trouvée sur le code Google, static-dll-bootstrapper .

10
Matt M

Vous pouvez utiliser System.load() pour fournir un chemin absolu comme vous le souhaitez, plutôt qu'un fichier dans le dossier de bibliothèque standard du système d'exploitation correspondant.

Si vous souhaitez que des applications natives existent déjà, utilisez System.loadLibrary(String filename) . Si vous voulez fournir le vôtre, vous êtes probablement mieux avec load ().

Vous devriez également pouvoir utiliser loadLibrary avec le Java.library.path correctement défini. Voir ClassLoader.Java pour la source d'implémentation affichant les deux chemins en cours de vérification (OpenJDK)

7
Philip Whitehouse

Dans le cas où le problème est que System.loadLibrary ne peut pas trouver le DLL en question, une idée fausse commune (renforcée par le message d'erreur de Java) est que la propriété système Java.library.path est la réponse. Si vous définissez la propriété système Java.library.path dans le répertoire où se trouve votre DLL, System.loadLibrary trouvera effectivement votre DLL. Toutefois, si votre DLL dépend à son tour d'autres DLL, comme c'est souvent le cas, Java.library.path ne peut vous aider, car le chargement des DLL dépendantes est entièrement géré par le système d'exploitation. Java.library.path. Par conséquent, il est presque toujours préférable de contourner Java.library.path et d'ajouter simplement le répertoire de votre DLL à LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) ou Path (Windows) avant de démarrer la machine virtuelle Java.

(Remarque: j'utilise le terme "DLL" au sens générique de DLL ou de bibliothèque partagée.)

6
Ian Emmons

Si vous devez charger un fichier relatif à un répertoire dans lequel vous êtes déjà (comme dans le répertoire actuel), voici une solution simple:

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());
3
Rick C. Hodgin

Pour ceux qui recherchent Java.lang.UnsatisfiedLinkError: no pdf_Java in Java.library.path

Je faisais face à la même exception; J'ai tout essayé et les choses importantes pour que ça marche sont:

  1. Version correcte de pdf lib.jar (dans mon cas, il s'agissait d'une mauvaise version conservée dans le serveur d'exécution)
  2. Créez un dossier, conservez le fichier jar pdflib et ajoutez-le dans votre variable PATH.

Cela a fonctionné avec Tomcat 6.

2
Mangesh M. Kulkarni

Pauvre de moi ! passé une journée entière derrière cela. L’écrire ici si un organisme quelconque reproduit ce problème.

J'essayais de charger comme suggéré par Adam, mais je me suis retrouvé pris avec l'exception d'AMD64 vs IA 32. votre JRE ET JDK sont en 64 bits et vous l'avez correctement ajouté à votre chemin d'accès aux classes.

Mon exemple de travail va ici: erreur de lien non satisfait

2
sayannayas
  1. Si vous pensez avoir ajouté un chemin de bibliothèque native à% PATH%, testez-vous une fois de plus en:

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

Cela devrait vous montrer réellement si votre dll est sur% PATH%

  1. Ne redémarrez pas IDE Idée, oui, cela semblait fonctionner pour moi après avoir configuré la variable env en l'ajoutant à% PATH%
1
AlexPes

Pour Windows, j’ai constaté que, lorsque j’ai chargé les filles (appels jd2xsx.dll et ftd2xx.dll) dans le dossier windowws/system32, le problème a été résolu. J'ai ensuite eu un problème avec mon plus récent fd2xx.dll en ce qui concerne les paramètres, c'est pourquoi j'ai dû charger l'ancienne version de cette dll. Je vais devoir trouver cela plus tard.

Remarque: le fichier jd2xsx.dll appelle le fichier ftd2xx.dll. Il peut donc ne pas être simple de définir le chemin d'accès au fichier jd2xx.dll.

0
Dan Carte

J'ai eu le même problème et l'erreur était due à un changement de nom de la DLL . Il est possible que le nom de la bibliothèque soit également écrit quelque part à l'intérieur de la dll . Lorsque j'ai remis son nom d'origine, j'ai pu charger en utilisant System.loadLibrary

0

J'utilise Mac OS X Yosemite et Netbeans 8.02. J'ai la même erreur et la solution simple que j'ai trouvée est la même que ci-dessus. C'est utile lorsque vous devez inclure une bibliothèque native dans le projet. Alors faites la prochaine pour 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

J'espère que cela pourra être utile à quelqu'un . Le lien où j'ai trouvé la solution est ici: Java.library.path - Qu'est-ce que c'est et comment l'utiliser

0
Alex Ventura

C'est simple, il suffit d'écrire Java -XshowSettings: les propriétés de votre ligne de commande dans Windows, puis de coller tous les fichiers dans le chemin indiqué par Java.library.path.

0
Ali Sasoli