web-dev-qa-db-fra.com

install_name_tool pour mettre à jour un exécutable afin de rechercher dylib dans Mac OS X

J'ai un libray dynamique libtest.dylib qui est installé dans /PATH/lib, et un binaire d’exécution, myapp, qui utilise le dylib installé dans /PATH/bin.

Je peux exécuter myapp pour trouver le fichier dylib comme suit ( Peut-on utiliser DYLD_LIBRARY_PATH sur Mac OS X? Et quel est l'algorithme de recherche de bibliothèque dynamique? ):

DYLD_LIBRARY_PATH="/PATH/lib" myapp 

Je pense que je peux utiliser install_name_tool pour mettre à jour la bibliothèque et l'exécutable afin que la bibliothèque puisse être trouvée avec rpath. J'ai utilisé les astuces dans ce post - Comment puis-je spécifier le rpath dans un dylib? .

Dans lib, j'ai exécuté cette commande pour ajouter rpath.

install_name_tool -id "@rpath/libtest.dylib" libtest.dylib
install_name_tool -add_rpath "@executable_path/../lib/" libtest.dylib

Dans bin, j'ai exécuté install_name_tool -add_rpath "@executable_path/../lib/" myapp.

Cependant, lorsque j'ai exécuté myapp dans le répertoire bin, j'ai les messages d'erreur.

dyld: Library not loaded: libtest.dylib
  Referenced from: /PATH/bin/./myapp
  Reason: image not found
Trace/BPT trap: 5

otool -l myapp montre que rpath est correctement mis à jour dans myapp.

Load command 16
          cmd LC_RPATH
      cmdsize 40
         path @executable_path/../lib/ (offset 12)

La même chose est vraie avec libtest.dylib

Load command 13
          cmd LC_RPATH
      cmdsize 40
         path @executable_path/../lib/ (offset 12)

Quel est le problème?

AJOUTÉE

Bien sûr, je peux utiliser cc -install_name quand compiler et lier du temps, mais je voulais savoir comment faire la même chose en modifiant le binaire généré et le binaire d’exécution.

De la lib:

cc -install_name "@loader_path/../lib/libtest.dylib" -dynamiclib -o libtest.dylib test.c

Ou, le nom_installation peut utiliser @rpath:

cc -install_name "@rpath/libtest.dylib" -dynamiclib -o libtest.dylib test.c

De la corbeille:

cc -I../lib -c main.c
cc -o main main.o ../lib/libtest.dylib -Wl,-rpath -Wl,@loader_path/../lib

Ou juste une ligne:

cc -I../lib -L../lib -o main main.c -ltest -Wl,-rpath -Wl,@loader_path/../lib
35
prosseek

De otool -l, J’ai analysé ce qui devrait être ajouté ou modifié à partir de la bibliothèque d’origine et binaire.

Dylib

Le changement est dans l'id:

Load command 2 <-- OLD
          cmd LC_ID_DYLIB
      cmdsize 40
         name libtest.dylib (offset 24)
   time stamp 1 Wed Dec 31 18:00:01 1969

Load command 2 <-- NEW
          cmd LC_ID_DYLIB
      cmdsize 64
         name @loader_path/../lib/libtest.dylib (offset 24)

C'est la commande pour accomplir le changement:

install_name_tool -id "@loader_path/../lib/libtest.dylib" libtest.dylib 

Ou utilisez rpath:

install_name_tool -id "@rpath/libtest.dylib" libtest.dylib

L'exécutable

Il y a deux changements: rpath et load_dylib

Load command 12 <-- OLD
          cmd LC_LOAD_DYLIB
      cmdsize 40
         name libtest.dylib (offset 24)

Load command 12 <-- NEW
          cmd LC_LOAD_DYLIB
      cmdsize 64
         name @loader_path/../lib/libtest.dylib (offset 24)

Ceci est la commande pour accomplir le changement

install_name_tool -change libtest.dylib @loader_path/../lib/libtest.dylib myapp 

Aussi j'avais besoin d'ajouter le rpath

Load command 14
          cmd LC_RPATH
      cmdsize 32
         path @loader_path/../lib (offset 12)

C'est la commande pour accomplir l'addition:

 install_name_tool -add_rpath "@loader_path/../lib" myapp

L'idée

Le binaire essaie de trouver la bibliothèque, il sait où il se trouve à partir de install_name_tool -add_rpath "@loader_path/../lib" myapp. Il charge la bibliothèque et son identifiant est @rpath/libtest.dylib@rpath est réglé sur @loader_path/../lib dans le binaire exécutable pour faire la correspondance.

Référence

Cmake

Lors de l'utilisation de CMake, nous pouvons automatiser le processus avec l'ajout suivant dans le fichier CMakeLists.txt.

L'identifiant devrait être ajouté.

# https://cmake.org/pipermail/cmake/2006-October/011530.html
SET_TARGET_PROPERTIES (test
  PROPERTIES BUILD_WITH_INSTALL_RPATH 1
             INSTALL_NAME_DIR "@rpath"
  )

Le rpath doit être spécifié:

SET(CMAKE_INSTALL_RPATH "@loader_path/../lib/libtest.dylib")
37
prosseek