2010-03-24 4 views
0

J'utilise JNA et Java mais je pense que cette question affecte tout pont natif-à-natif.chemins de recherche où une bibliothèque native dépend d'une autre

J'ai une application Java qui repose sur lib1.dylib, et lib1.dylib repose sur lib2.dylib.

Je veux mettre tout à l'intérieur de mon fichier .app sur Mac. Je peux facilement mettre lib1.dylib à l'intérieur et mettre java.classpath (ou NativeLibrary.addSearchPath()) pour dire à la JVM où trouver lib1.dylib. Le problème est, je ne sais pas comment communiquer que les dépendances de lib1.dylib sont également dans l'emplacement que j'ai fourni. Le résultat est que lib1 est bien chargé, mais que lib2 ne peut pas être trouvé car il ne se trouve pas dans le chemin de la bibliothèque du système d'exploitation.

Quelqu'un sait comment je peux surmonter ce problème? J'imagine que cela doit arriver beaucoup dans les grands projets avec un grand nombre de bibliothèques partagées.

Répondre

2

J'ai déjà rencontré ce problème et je l'ai encore rencontré aujourd'hui. Vous pouvez peut-être contourner le problème en ajoutant l'argument VM "-Djava.library.path =/chemin/vers/autre/libs", mais je crois me souvenir que Java ne l'utilise que pour rechercher la bibliothèque intial, puis utilise le système PATH pour rechercher les dépendances.

Quelques solutions que j'ai essayé avant:

1) Utilisation System.load (AbsolutePath) sur la bibliothèque dépendante avant de charger votre bibliothèque. Cela ne rend pas votre programme ultra-portable, sauf si vous savez toujours où cette bibliothèque va être.

2) Dans le cas où lib1 dépend de lib2, j'ai utilisé SetCurrentDirectory (Windows, pas sûr de l'équivalent Mac) dans le code natif avant qu'il ne soit lié à l'une des bibliothèques dépendantes, et cela a semblé fonctionner. Encore une fois, nécessite de savoir où sont les autres bibliothèques.

3) Sous Windows, il est possible de vider les bibliothèques dépendantes dans c: \ windows \ system32, et il les trouve.

Quelques messages utiles sur un sujet similaire (Windows spécifique, mais je pense que le problème est le même):

http://www.realityinteractive.com/rgrzywinski/archives/000219.html http://www.velocityreviews.com/forums/t387618-jni-library-path.html

+0

Merci! Je vérifierai. Désolé de confondre classpath et java library path dans ma question. (1) ou (2) peut valoir la perte de la portabilité. J'essaie d'éviter (3) car cela complique grandement l'installateur, nécessite un accès root, risque d'écraser les anciennes versions de libs dont d'autres applications ont besoin, etc.: - \ –

+0

Après avoir étudié ces options, rien que de mauvaises nouvelles. (1) Ne fonctionne pas avec JNA. Apparemment, JNA ne se soucie pas de savoir si Java a déjà chargé la bibliothèque, vraisemblablement parce qu'elle doit faire ses propres tâches de cartographie. Cela fonctionnerait cependant avec JNI. (2) nécessiterait un code spécial pour différents systèmes d'exploitation, mais le plus problématique est qu'il n'y a pas d'équivalent à dllmain sous UNIX et aucune garantie spécifique (que je sache) que le commutateur cwd sera exécuté avant que la recherche de dépendances soit terminée. Je ne vois pas d'alternative à (3) que j'essayais d'éviter avec cette question. Bummer. –

0

que j'ai trouvé une solution pour MacOSX basée sur l'idée Dans (2) de Stew:

En utilisant Mac JarBundler (ou la tâche Ant du même nom) définissez la variable de travail de travail à $ JAVAROOT et assurez-vous que vos dylibs sont dans la partie Contents/Resources/Java du .app. Si vous faites cela, l'éditeur de liens dynamiques trouvera toutes les dylibs de dépendance car ce sera le répertoire actuel. Java trouvera également le dylib original (celui qui a toutes les dépendances) pour la même raison.

Code Ant:

<target name="package_mac_app" depends="package_jar, compile_native" description="bundle the runnable jar into a Mac Application -- requires JarBundler ANT Task"> 
    <taskdef name="jarbundler" classname="net.sourceforge.jarbundler.JarBundler"/> 
    <echo message="CREATING MAC .app EXECUTABLE"/> 
    <jarbundler dir="${dist}" 
     name="${appname}" 
     mainclass="myPackage.myMainClass" 
     icon="${icon_location}" 
     jvmversion="1.5+" 
     infostring="${appname}" 
     shortname="${appshortname}" 
     bundleid="${com.mycompany.mydepartment.myprogram}" 
     jar="${run_jar_location}" 
     workingdirectory="$JAVAROOT"> 
     <javafilelist dir="${dylib_location}" files="my-lib.dylib"/> 
     <javafilelist dir="${dylib_location}" files="dependent-lib.dylib"/> 
    </jarbundler> 

</target> 
+0

Nice. Je pourrais essayer ceci sur un de mes projets. C'est assez propre et correspond toujours à toute l'installation 'glisser-déposer'. – Stew

Questions connexes